模板函数中使用的类的前向声明不是由 clang++ 编译的

Forward declaration of class used in template function is not compiled by clang++

本文关键字:声明 编译 clang++ 函数      更新时间:2023-10-16

有这段代码:

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(主干)给出了这个错误:

main.cpp:5:6: error: variable has incomplete type 'A'
   A a;
     ^
main.cpp:1:7: note: forward declaration of 'A'
class A;
      ^

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

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

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

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

clang++ 和其他编译器确实在这里发出诊断是一个不错的附加功能,但诊断不是强制性的。该条款"程序格式不正确;无需诊断",使编译器开发人员可以自由地在这种情况下执行几乎任何事情,并且仍然合规。

我所知,Clang是正确的。在你的函数乐趣中,你不知道 A 的大小,既然你分配了一个 A,你需要知道它的大小。在我看来,gcc 是在这里宽恕的方式。

clang++使用正确的行为,这在标准(N1905)的第4.6/9节中有描述。


Templates 14.6/9 Name resolution

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


用更简单的术语来说;如果名称依赖于模板参数,它应该在找到定义的范围内;因此你需要在定义template<typename T> void fun ()之前定义A

Comeau的编译器也不喜欢它:

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

然而,我试图在C++标准中找到章节和经文,但没有结果。它似乎隐藏在"实例化点"、"名称解析"的行间和交互之间。2003年标准第14.6/8段和第14.6/9段似乎具有相关性。