为什么 clang++ 在遇到模板类的公共静态浮点成员变量时无法推迟符号解析?

问题描述 投票:0回答:1

当使用模板类的

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 中的编译器错误吗?有解决办法吗?

c++ templates clang++
1个回答
0
投票

这个警告似乎只是 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
视为常量表达式并假设类不需要定义即可使成员有用。这可能是警告的一个例外,以避免一些误报。

© www.soinside.com 2019 - 2024. All rights reserved.