考虑下面的代码,它带有明显的编译错误:(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/