在编译C ++时,gcc和clang似乎推迟了模板实例化的类型检查,直到处理完所有程序声明之后。这是用语言保证的吗?
详细说明,我可以在定义模板或需要模板实例化的位置保持类型不完整,只要我在程序中的某个地方完成该类型:
class A;
class B;
extern A* pa;
// 1. template definition
template<typename T>
T* f() { return static_cast<T*>(pa); }
// 2. template instantiation
B* test() { return f<B>(); }
// 3. completing types
class A { };
class B : public A { };
请注意,A和B的定义需要键入检查模板实例化(以使static_cast有效)。如果省略第3步,则第2步将不再编译。
在我的标题组织中,我可以依赖任何标准C ++编译器接受此顺序吗?
答案 0 :(得分:5)
该规则称为“两阶段名称查找”。
在定义时查找并检查不依赖于模板参数的名称,并在实例化时检查依赖名称。
对于您的示例,有一个重要细节:翻译单元的结尾也被视为功能模板的实例化点:
C ++ 14 N4140 14.6.4.1 [temp.point] P8:
功能模板,成员函数模板或成员函数或静态的特化 类模板的数据成员可以在翻译单元内具有多个实例化点,以及 除了上面描述的实例化点之外,对于任何具有重点的专业化 在翻译单元内的实例化中,翻译单元的末尾也被认为是一个点 实例
因此,尽管类型在点“2”处是不完整的,但是在显式实例化发生时,它在文件末尾完成,这使得模板实例化合法。
注意:Microsoft编译器未完全实施此规则,违反了标准。在Microsoft编译器中,所有查找都在实例化时发生(因此该示例也应该有效,但我无法访问MSVC进行检查)。其他主要编译器确实正确实现了此规则。