当使用模板类的
public
、static
浮点成员变量时,clang 编译失败(当警告被视为错误时),而不是将符号解析推迟到链接时间。对于类似作用域的整数成员变量来说,情况并非如此,其中 clang 在链接时正确失败(如果未提供类的定义)。
GCC 同样对待浮点和整数成员变量:在这两种情况下,它都会在链接时失败。行为比较这里,在编译器资源管理器中。
#include <iostream>
template <class T>
void func(T& p_arg) {
std::cout << p_arg << std::endl;
}
template <class T>
struct Foo {
static const int s_default_int;
static const double s_default_dbl;
T my_T;
};
int main() {
using t_Foo = Foo<short>;
// GCC and clang fail on link
func(t_Foo::s_default_int);
// GCC fails on link
// clang fails during *compilation*
func(t_Foo::s_default_dbl);
}
叮当:
<source>:23:17: error: instantiation of variable 'Foo<short>::s_default_dbl' required here, but no definition is available [-Werror,-Wundefined-var-template]
func(t_Foo::s_default_dbl);
^
<source>:11:25: note: forward declaration of template entity is here
static const double s_default_dbl;
^
<source>:23:17: note: add an explicit instantiation declaration to suppress this warning if 'Foo<short>::s_default_dbl' is explicitly instantiated in another translation unit
func(t_Foo::s_default_dbl);
^
1 error generated.
海湾合作委员会:
<source>:19: undefined reference to `Foo<short>::s_default_int'
这是 clang 中的编译器错误吗?有解决办法吗?
这个警告似乎只是 Clang 试图警告您稍后可能会遇到链接器错误。以下是开发人员对警告以及如何使用它的意见:https://github.com/dealii/dealii/issues/3705#issuecomment-1175596077
如果
Foo
在 cpp 文件中显式实例化,编译器还看不到它并会发出警告。在这种情况下,您可以使用类似 extern template struct Foo<short>;
的内容声明显式实例化,以便编译器假定其他地方存在显式实例化。
如果稍后未显式实例化
Foo
,则警告似乎是正确的,并且应将静态成员的定义添加到标头中。
GCC 在编译期间不抱怨的原因是该代码没有本地错误。仅当在链接期间将所有翻译单元视为一个整体时才会发生该错误。 Clang 发出警告,表示稍后可能会出现问题,但不会直接抱怨翻译单元内出现问题。据我所知,GCC 没有等效的警告,因此该行为无法重复。
至于为什么 Clang 会警告
s_default_dbl
而不是 s_default_int
,我不确定。看来警告应该适用于这两种情况。我推测这可能与整数类型的const静态数据成员可以被视为常量表达式有关,而浮点成员则不能。前任。 static const int s_default_int = 10;
没问题,您可以将其用作常量表达式,例如 char my_array[Foo<int>::s_default_int];
,但不允许使用 static const double s_default_dbl = 42.0;
(您需要显式地使其为 constexpr
)。编译器可能会混淆将 s_default_int
视为常量表达式并假设类不需要定义即可使成员有用。这可能是警告的一个例外,以避免一些误报。