编译器如何生成模板类定义?

时间:2016-03-25 00:08:36

标签: c++ templates

考虑以下头文件。

在我的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_

然后我创建了两个具有不同哈希值的策略P1和P2。

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_

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_

main.cpp我有

#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();
}
OS X上的

结果

hash = 1

hash = 0

观察

  1. 它将编译并正常运行。请注意,Object<P2>的定义甚至不完整。由于P2尚未定义setHash()。

  2. 如果我在主要内容中删除评论,则会报告错误。

    ./ Object.h:20:8:错误:'P2'中没有名为'setHash'的成员

    main.cpp:12:6:注意:在成员函数'Object :: set'的实例化中请求t2.set();

  3. 问题

    1. 考虑P1或P2类中的Object成员,即使我没有在main中创建Object<P1>Object<P2的实例,编译器也会为每个成员生成类定义吗?

    2. 为什么Object<P2>可以?由于定义不完整。

2 个答案:

答案 0 :(得分:1)

Object<P1>Object<P2>内没有P1P2个成员。有Object<P1>*Object<P2>*个成员。指向不完整类型的指针完全可以。除非指针被取消引用,否则不会实例化类型本身。

main函数中,Object<P2>是一个完整的类型,但除非被调用(或者更确切地说,技术上,使用ODR),它的非虚拟成员函数仍未实例化。这就是拥有Object<P2> t2;但调用t2.set()是错误的原因。

答案 1 :(得分:1)

  

考虑P1或P2类中的Object成员,即使我没有在main中创建Object<P1>Object<P2>的实例,编译器也会为每个成员生成类定义吗?

没有。成员为Object<P1>* t;Object<P1>* t; - 他们不是static,因此仅在创建P1P2对象实例时创建,并且&#{1}} 39;重新指针,即使这样也没有创建Object<P1>*:传递给构造函数的指针 - 可能是nullptr / 0 - 只是存储。

  

为什么对象没问题?由于定义不完整。

使用模板,函数仅在被调用时被实例化。只要它们可以正确解析,就不是错误。