考虑下面的代码,它带有明显的编译错误:(1)

struct A;
struct B {
  B() { new A(); } // error: allocation of incomplete type 'A'
};


使用unique_ptr不能帮助:(2)

struct A;
struct B {
  B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};


然后(令我惊讶的是)我发现,它将进行编译:(3)

struct A;
struct B {
  B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**


然后我检查了这是否也有助于new-不:(4)

struct A;
struct B {
  B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};


我发现它与template有关,实际上:将new包裹在template中确实可以编译:(5)

template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
  B() { my_new<A>(); }
};
struct A {};


为了完整起见,删除A的定义会再次引发错误:(6)

template <typename T>
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
  B() { my_new<A>(); }
};
// do note: definition of A removed


这里发生了什么?据我了解,编译器必须知道A的大小/定义才能分配它,因此仅声明它是不够的。另外,我认为,定义必须先于分配。

直接使用new(1,4)时,这似乎是正确的。但是,当new被包装时,很明显我弄错了(2,3,5,6)。

到目前为止,我发现的可能解释是:


完成类型的检查将延迟到template实例化发生之前。我认为这是正确的,但就我而言,直接使用new A()和对my_new<A>()的调用实际上发生在同一位置。因此,这不是原因。对?
将不完整的类型用作template参数可能是未定义的行为。这是真的吗?即使启用所有警告,编译器也不会抱怨。比较5和6似乎也暗示了编译器足够聪明,可以找出下面的定义(因此实际上使类型完整)。


为什么4被认为是不正确的,而5却被编译(或者5只是虚假地编译未定义的行为[但是3也必须是有缺陷的,对吗?))?

btw:使用clang ++-3.5.0和g ++-4.9.2测试

最佳答案

§14.6.4.1[温度点] / p1,8,重点是:


  1对于功能模板专业化,成员功能模板
  专门化,或成员函数或静态的专门化
  类模板的数据成员,如果专门化是隐式的
  实例化,因为它是从另一个模板中引用的
  专业化及其引用的上下文取决于
  模板参数,专业化的实例化点
  是封闭专业化的实例化点。
  否则,这种专业化的实例化点
  立即遵循名称空间范围声明或定义
  是指专业化。
  
  8功能模板,成员功能模板的专业化,
  或类模板的成员函数或静态数据成员的
  在翻译单元中有多个实例化点,并且
  除上述实例化点外,对于任何
  这样的专业化在内部具有实例化点
  翻译单元,翻译单元的末尾也被认为是
  实例化点。类模板的专业化之处在于
  翻译单元中的最多一个实例化点。一种
  任何模板的专业化可能在
  多个翻译单元。如果两个不同的实例化点
  根据一个模板给模板专门化不同的含义
  定义规则(3.2),程序格式错误,无诊断
  需要。


my_new<A>有两个实例化点,一个在B定义的末尾,另一个在转换单元的末尾。由于这两点将导致不同的含义(对于摘要3和5),因此程序的格式不正确,即NDR(即,其行为未定义)。

关于c++ - 包装在模板中时,新的不完整类型编译,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38926802/

10-14 06:09