模板类中静态变量的 Decltype

xEr*_*_xD 5 c++ templates decltype

我正在尝试使用 clang 在类范围之外定义模板类的静态变量:

class Bar
{
public:
    float a;
};

template<long count>
class Foo {
public:
    static Bar* test;
};

template<long count>
decltype(Foo<count>::test) Foo<count>::test; // error

int main() {
    Foo<5> f;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误: error: redefinition of 'test' with a different type: 'decltype(Foo<count>::test)' vs 'Bar *'

在我看来decltype(Foo<count>::test)应该评估为Bar *.

这段代码在 MSVC 上运行良好。

我的问题:有没有办法decltype在这里正确确定类型?

在实际代码中,decltype是在一个宏中定义的,该宏具有一些附加关键字,具体取决于所使用的配置,所以我希望在仍然使用decltype.

Jan*_*tke 6

此代码格式不正确,因为decltype(Foo<count>::test)表示唯一类型,即使它等效于Bar*.

\n

相关标准章节如下:

\n
\n

如果两个声明(重新)引入相同的名称、都声明构造函数或都声明析构函数,则它们对应,除非 [...]

\n
\n

- basic.scope.scope \xc2\xa74

\n

我们甚至看到了一个例子,声明不必在符号上相同即可对应:

\n
\n
typedef int Int;\n/* ... */\nvoid f(int);                    // #1\nvoid f(Int) {}                  // defines #1\n
Run Code Online (Sandbox Code Playgroud)\n
\n

- basic.scope.scope - 示例 2

\n

然而,decltype在这方面有特殊之处:

\n
\n

如果表达式e类型相关的decltype(e)则表示唯一的相关类型。\n仅当两个此类decltype说明符的表达式等效 ( [temp.over.link] ) 时,它们才引用同一类型。

\n
\n

-临时类型\xc2\xa74

\n

在你的例子中:

\n
// variable type declared as Bar* elsewhere\ntemplate<long count>\ndecltype(Foo<count>::test) Foo<count>::test;\n
Run Code Online (Sandbox Code Playgroud)\n

decltype(Foo<count>::test)依赖于count,因此类型是唯一的并且与 不同Bar*。\n证明它们对于任意表达式都是相同的在一般情况下是不可判定的,因此编译器不允许这样做是有道理的。

\n

GCC 错误地编译了您的示例(请参阅编译器资源管理器),但 clang 和 MSVC 不会。\n这可能是因为 GCC 不将其视为test依赖项,因为它是用 type 声明的Bar*,而类型不是依赖项。\n但是,不符合要求。

\n

结论

\n

最好的做法是找到一种方法来用相同的类型定义这种外线:

\n
template<long count>\nBar* Foo<count>::test;\n
Run Code Online (Sandbox Code Playgroud)\n

如果你不能Bar*直接使用,也许还有另一种方法可以让你的使用decltype不依赖于count.

\n

或者,您也可以定义static成员inline(C++17 起):

\n
template<long count>\nclass Foo {\npublic:\n    static inline Bar* test = ...;\n};\n
Run Code Online (Sandbox Code Playgroud)\n
\n

注意:我个人也遇到过类似的问题,编译器无法将成员函数的外线定义与类中的声明相匹配。

\n