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.
此代码格式不正确,因为decltype(Foo<count>::test)表示唯一类型,即使它等效于Bar*.
相关标准章节如下:
\n\n\n\n如果两个声明(重新)引入相同的名称、都声明构造函数或都声明析构函数,则它们对应,除非 [...]
\n
我们甚至看到了一个例子,声明不必在符号上相同即可对应:
\n\n\n\nRun Code Online (Sandbox Code Playgroud)\ntypedef int Int;\n/* ... */\nvoid f(int); // #1\nvoid f(Int) {} // defines #1\n
然而,decltype在这方面有特殊之处:
\n\n\n如果表达式
\ne是类型相关的,decltype(e)则表示唯一的相关类型。\n仅当两个此类decltype说明符的表达式等效 ( [temp.over.link] ) 时,它们才引用同一类型。
在你的例子中:
\n// variable type declared as Bar* elsewhere\ntemplate<long count>\ndecltype(Foo<count>::test) Foo<count>::test;\nRun Code Online (Sandbox Code Playgroud)\ndecltype(Foo<count>::test)依赖于count,因此类型是唯一的并且与 不同Bar*。\n证明它们对于任意表达式都是相同的在一般情况下是不可判定的,因此编译器不允许这样做是有道理的。
GCC 错误地编译了您的示例(请参阅编译器资源管理器),但 clang 和 MSVC 不会。\n这可能是因为 GCC 不将其视为test依赖项,因为它是用 type 声明的Bar*,而类型不是依赖项。\n但是,不符合要求。
最好的做法是找到一种方法来用相同的类型定义这种外线:
\ntemplate<long count>\nBar* Foo<count>::test;\nRun Code Online (Sandbox Code Playgroud)\n如果你不能Bar*直接使用,也许还有另一种方法可以让你的使用decltype不依赖于count.
或者,您也可以定义static成员inline(C++17 起):
template<long count>\nclass Foo {\npublic:\n static inline Bar* test = ...;\n};\nRun Code Online (Sandbox Code Playgroud)\n注意:我个人也遇到过类似的问题,编译器无法将成员函数的外线定义与类中的声明相匹配。
\n