有这段代码:
class A;
template <class T>
void fun() {
A a;
}
class A {
public:
A() { }
};
int main() {
fun<int>();
return 0;
}
g ++ 4.5和g ++ 4.7编译时没有错误。但是clang ++ 3.2(trunk)给出了这个错误:
main.cpp:5:6: error: variable has incomplete type 'A'
A a;
^
main.cpp:1:7: note: forward declaration of 'A'
class A;
^
根据C ++标准,哪个编译器正确?
答案 0 :(得分:12)
根据C ++标准,哪个编译器正确?
两者都是正确的。这是一个不正常的计划。强调我的:
N329014.6¶9
如果非依赖名称中使用的类型在定义模板但在完成实例化时完成,并且该类型的完整性影响程序是否良好时,则不完整形成或影响程序的语义,程序形成不良;无需诊断。
clang ++和其他编译器确实在这里发出诊断是一个很好的补充功能,但诊断并不是强制性的。该条款“该程序格式不正确;不需要诊断”使编译器开发人员可以在这种情况下自由执行任何操作,并且仍然符合要求。
答案 1 :(得分:5)
答案 2 :(得分:1)
clang++
正在使用正确的行为,标准部分4.6/9
( n1905 )中对此进行了描述。
<强>
Templates 14.6/9 Name resolution
强>如果名称不依赖于模板参数(如中所定义) 14.6.2 ),该名称的声明(或一组声明)应在名称出现在模板中的范围内 定义;名称与声明(或声明)绑定 在那一点上找到并且此绑定不受声明的影响 在实例化时可见。
简单易懂;如果名称不依赖于模板参数,则它应该在找到定义的范围内;因此,您需要在定义A
之前定义template<typename T> void fun ()
。
答案 3 :(得分:0)
Comeau的编译器也不喜欢它:
"ComeauTest.c", line 5: error: incomplete type is not allowed
A a;
^
然而,我在C ++标准中寻找章节和诗句的尝试毫无结果。它似乎隐藏在“实例化点”,“名称解析”的界限和交互之间。 2003年标准的第14.6 / 8和14.6 / 9段似乎是相关的。