C++ 当包装到模板中时,不完整类型的新文件将编译
考虑这段代码,其中有一个明显的编译错误:(1) 使用C++ 当包装到模板中时,不完整类型的新文件将编译,c++,templates,forward-declaration,C++,Templates,Forward Declaration,考虑这段代码,其中有一个明显的编译错误:(1) 使用唯一\u ptr也不会有任何帮助:(2) 我认为它与模板s有关,事实上:在模板中包装新的,编译:(5) 这是怎么回事?据我所知,编译器必须知道A的大小/定义才能分配它,因此仅仅声明它是不够的。此外,我认为定义必须在分配之前 当直接使用new时,这似乎是正确的(1,4)。但是当new被包装时,很明显我错了(2,3,5,6) 到目前为止,我发现的可能解释如下: 对已完成类型的检查延迟到模板实例化发生。我认为这是正确的,但在我的例子中,直接使用ne
唯一\u ptr
也不会有任何帮助:(2)
我认为它与模板
s有关,事实上:在模板
中包装新的
,编译:(5)
这是怎么回事?据我所知,编译器必须知道A
的大小/定义才能分配它,因此仅仅声明它是不够的。此外,我认为定义必须在分配之前
当直接使用new
时,这似乎是正确的(1,4)。但是当new
被包装时,很明显我错了(2,3,5,6)
到目前为止,我发现的可能解释如下:
- 对已完成类型的检查延迟到
实例化发生。我认为这是正确的,但在我的例子中,直接使用模板
和调用newa()
几乎发生在同一位置。所以这不可能是原因。对吧?my_new()
- 使用不完整的类型作为
参数可能是未定义的行为。这是真的吗?即使启用所有警告,编译器也不会抱怨。同样,比较5和6似乎表明,编译器足够聪明,能够理解以下定义(从而实际上使类型完整)模板
顺便说一句:使用clang++-3.5.0和g++-4.9.2测试[temp.point]/p1,8,强调: 1对于函数模板专用化,成员函数模板 专门化,或成员函数或静态函数的专门化 类模板的数据成员,如果专门化是隐式的 已实例化,因为它是从另一个模板中引用的 专门化及其引用所依赖的上下文 模板参数,专门化的实例化点 是封闭专门化的实例化点。 否则,这种专门化的实例化点 紧跟在 指专业化。 8函数模板、成员函数模板的专门化, 或类模板的成员函数或静态数据成员的 在翻译单元内有多个实例化点,以及 除了上述实例化点之外,对于任何 这种专门化在 翻译单元,翻译单元的末尾也被视为 实例化点。类模板的专门化至少具有 大多数情况下,在翻译单元中只有一个实例化点。A. 任何模板的专门化都可能在 多个翻译单元如果两个不同的实例化点 根据一个模板给出不同的含义 定义规则(3.2),程序格式错误,无诊断 必需。
my_new
有两个实例化点,一个在B
定义的末尾,另一个在翻译单元的末尾。由于这两点将产生不同的含义(对于代码段3和5),因此程序是格式错误的NDR(即,它具有未定义的行为)。§14.6.4.1[临时点]/p1,8,重点:
1对于函数模板专用化,成员函数模板
专门化,或成员函数或静态函数的专门化
类模板的数据成员,如果专门化是隐式的
已实例化,因为它是从另一个模板中引用的
专门化及其引用所依赖的上下文
模板参数,专门化的实例化点
是封闭专门化的实例化点。
否则,这种专门化的实例化点
紧跟在
指专业化。
8函数模板、成员函数模板的专门化,
或类模板的成员函数或静态数据成员的
在翻译单元内有多个实例化点,以及
除了上述实例化点之外,对于任何
这种专门化在
翻译单元,翻译单元的末尾也被视为
实例化点。类模板的专门化至少具有
大多数情况下,在翻译单元中只有一个实例化点。A.
任何模板的专门化都可能在
多个翻译单元如果两个不同的实例化点
根据一个模板给出不同的含义
定义规则(3.2),程序格式错误,无诊断
必需。
my_new
有两个实例化点,一个在B
定义的末尾,另一个在翻译单元的末尾。由于这两点将导致不同的含义(对于代码片段3和5),因此程序是格式错误的NDR(即,它有未定义的行为)。如果不清楚,因为那篇文章只讨论了两阶段名称查找的更严格的方面,模板名称在代码的另一个阶段之前不会实例化,在它已经阅读并阅读了A
的定义之后,这就是它编译的原因。将模板实例化延迟到翻译单元结束是一种常见的实现技术。你的代码
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A;
struct B {
B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};
struct A;
struct B {
B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
B() { my_new<A>(); }
};
struct A {};
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