考虑以下代码:
template <typename T = int> struct X {};
extern X foo;
X foo;
我希望它的格式正确,但是GCC,Clang和MSVC拒绝它并显示以下错误消息:
GCC 8.2(带有-std=c++17 -Wall -Wextra -pedantic-errors
):
<source>:3:3: error: conflicting declaration 'X foo' X foo; ^~~ <source>:2:10: note: previous declaration as 'X<int> foo' extern X foo; ^~~
Clang 7.0.0(带有-std=c++17 -Wall -Wextra -pedantic-errors
):
<source>:2:10: error: declaration of variable 'foo' with deduced type 'X' requires an initializer extern X foo; ^
MSVC Pre 2018(带有/std:c++latest
):
<source>(2): error C2641: cannot deduce template argument for 'X' <source>(3): error C2133: 'foo': unknown size <source>(3): error C2641: cannot deduce template argument for 'X'
现在有趣的部分。
此代码段被Clang接受,但被GCC和MSVC拒绝:
extern X<> foo;
X foo;
此代码段已被GCC接受,但被Clang和MSVC拒绝:
extern X foo;
X<> foo;
所有三个编译器都接受此代码:
extern X<> foo;
X<> foo;
最后,这个被GCC和Clang接受,但被MSVC拒绝:
X foo;
这是怎么回事?这五个摘要中的哪一个是正确的?
答案 0 :(得分:3)
clang都是正确的。
extern X<> foo; // type: X<> X foo; // CTAD => type: X<>
foo
仅是foo
的声明,然后在以后使用相同的类型重新声明,因此gcc和MSVC拒绝这种情况是错误的。
extern X foo; // invalid X<> foo; // ok => type: X<>
gcc在这里是错误的。 foo
不是定义,只是没有初始化程序的声明,因此也不是CTAD(initializing declaration)所必需的[dcl.class.type.deduct]。
extern X<> foo; // type: X<> X<> foo; // type: X<>
这类似于1),仅不需要CTAD。由于第二个foo
只是foo
的重新声明,并且同时使用相同的类型对其进行定义,因此它是有效的。
X foo;
这里的MSVC是错误的,该标准在全球范围内对CTAD没有任何限制。
总而言之,我们可以推断出您的原始代码段格式错误,因为您将CTAD用于未定义的变量。