Lin
Lin

Reputation: 1595

How does compiler generate template class definitions?

Consider the following header files.

In my Object.h

#ifndef OBJECT_H_
#define OBJECT_H_

#include <iostream>

template <class Policy>
class Object
{
  friend Policy;
 private:
  Policy* p;
  int hash;

 public:
 Object():p(new Policy(this)),hash(0){}
  ~Object(){delete p;}

  void set(){p->setHash();}

  void show() const{std::cout<<"hash = "<<hash<<std::endl;}
};

#endif // OBJECT_H_

Then I created two Policies, P1 and P2, with different hash values.

In p1.h

#ifndef P1_H_
#define P1_H_

template <class Policy> class Object;

class P1
{
  enum {p1 = 1}; 
  Object<P1>* t;

 public:
  P1(Object<P1>* at):t(at){}
  void setHash(){t->hash = p1;}
};

#endif // P1_H_

In p2.h

#ifndef P2_H_
#define P2_H_

template <class Policy> class Object;
class P2
{
 enum {p2 = 2};

 Object<P2>* t;

 public:
 P2(Object<P2>* at):t(at){}
 //void setHash(){t->hash = p2;} // ** Notice here **
};
#endif // P2_H_

In my main.cpp I have

#include "Object.h"
#include "p1.h"
#include "p2.h"

int main()
{
  Object<P1> t1;
  t1.set();
  t1.show();

  Object<P2> t2;
  //t2.set();
  t2.show();
}

Result on OS X:

hash = 1

hash = 0

Observations:

  1. It will compile and run properly. Notice the definition of Object<P2> is even not complete. Since P2 have not defined setHash().

  2. If I get rid of the comment in my main, then it will report an error.

    ./Object.h:20:8: error: no member named 'setHash' in 'P2'

    main.cpp:12:6: note: in instantiation of member function 'Object::set' requested here t2.set();

Questions

  1. Consider the Object member inside P1 or P2 class would compiler generate class definition for each of them even if I do not create an instance of Object<P1> or Object<P2 in main?

  2. Why Object<P2> is OK? Since the definition is incomplete.

Upvotes: 0

Views: 71

Answers (2)

Tony Delroy
Tony Delroy

Reputation: 106216

Consider the Object member inside P1 or P2 class would compiler generate class definition for each of them even if I do not create an instance of Object<P1> or Object<P2> in main?

No. The members are Object<P1>* t; and Object<P1>* t; - they're not static so are only created when P1 and P2 object instances are created, and they're pointers so even then no Object<P1>* is created: the pointer passed to the constructor - which may be nullptr / 0 - is simply stored.

Why Object is OK? Since the definition is incomplete.

With templates, functions are only instantiated when called. As long as they can be parsed properly, it is not an error.

Upvotes: 1

n. m. could be an AI
n. m. could be an AI

Reputation: 120031

There are no Object<P1> or Object<P2> members inside P1 and P2. There are Object<P1>* and Object<P2>* members. A pointer to an incomplete type is perfectly OK. The type itself will not be instantiated unless the pointer is dereferenced.

In your main function, Object<P2> is a complete type, but its non-virtual member functions are still not instantiated unless called (or rather, technically, ODR-used). This is why it is OK to have Object<P2> t2; but calling t2.set() is an error.

Upvotes: 1

Related Questions