12

有这个代码:

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++ 标准,哪个编译器是正确的?

4

4 回答 4

12

根据 C++ 标准,哪个编译器是正确的?

两者都是正确的。这是一个格式错误的程序。强调我的:

N3290 14.6¶9
如果在非依赖名称中使用的类型在定义模板时是不完整的,但在实例化完成时是完整的,并且该类型的完整性是否会影响程序格式正确或影响程序的语义,程序格式错误;不需要诊断

clang++ 和其他编译器确实在这里发出诊断是一个不错的附加功能,但诊断不是强制性的。该条款“程序格式错误;不需要诊断”使编译器开发人员可以自由支配在这种情况下做任何事情并且仍然符合要求。

于 2012-06-12T12:59:11.663 回答
5

据我所知,Clang 是正确的。在你的函数 fun 中,你不知道 A 的大小,并且由于你分配了一个 A,你需要知道它的大小。在我看来,gcc 是一种宽容的方式。

于 2012-06-12T09:33:45.557 回答
1

clang++正在使用正确的行为,这4.6/9在标准 ( n1905 ) 部分中进行了描述。


Templates 14.6/9 Name resolution

如果名称不依赖于模板参数(如 14.6.2中定义),则该名称的声明(或声明集)应在该名称出现在模板定义中的点的范围内;该名称绑定到在该点找到的声明(或多个声明),并且此绑定不受在实例化点可见的声明的影响。


把事情简单地说;如果名称依赖于模板参数,则它应该在找到定义的范围内;因此,您需要在A定义template<typename T> void fun ().

于 2012-06-12T11:11:20.250 回答
0

Comeau 的编译器也不喜欢它:

"ComeauTest.c", line 5: error: incomplete type is not allowed
     A a;
       ^

然而,我在 C++ 标准中寻找章节和经文的尝试没有结果。它似乎隐藏在“实例化点”、“名称解析”的线条和交互之间。2003 年标准的第 14.6/8 和 14.6/9 段似乎相关。

于 2012-06-12T10:42:40.867 回答