<分区>
这始于观察。我更改了一些看起来有点像这样的代码(编辑:我在这里取出了指定的初始化器,它们也不在原始代码中):
struct S {
enum E { E1, E2 } member;
}
// file1.cc
S v1 = { S::E1 };
// file2.cc
S v2 = { S::S::E2 };
请注意 file2.cc
过度限定了 E2
。然而,这在 g++ 和 clang++ 中都有效。 (编辑 2:这个特定 VM 上的 g++ 是 g++-5.4.1,但原始代码已经通过早期和后来的 g++ 版本,加上多个 clang 版本。)事实上,我们可以写:
S v3 = { S::S::S::S::S::S::S::E1 };
(无论我们喜欢多少 S::
),无论我们喜欢什么。我改变了一些东西,使 S
不再是一个普通的 struct
,而是一个模板化的结构,之后它就停止工作了。没什么大不了的,但这让我很好奇,所以我进行了试验。
如果我们将其更改为非 POD 类型:
struct S {
S() { std::cout << "made an S" << std::endl; }
enum E { E1, E2 } member;
}
(使用适当的#include
)它不再被允许。 Clang 和 g++ 产生不同的诊断。这是 clang 的提示:
namespace.cc:8:3: error: no matching constructor for initialization of 'S'
S x = { .member = S::S::E1 };
namespace.cc:3:8: note: candidate constructor (the implicit copy constructor)
not viable: cannot convert argument of incomplete type 'void' to
'const S &' for 1st argument
struct S {
^
namespace.cc:3:8: note: candidate constructor (the implicit move constructor)
not viable: cannot convert argument of incomplete type 'void' to 'S &&'
for 1st argument
struct S {
^
namespace.cc:4:3: note: candidate constructor not viable: requires 0 arguments,
but 1 was provided
S() { std::cout << "made an S\n"; }
^
1 error generated.
和 g++ 的:
namespace.cc:8:28: error: could not convert ‘{E1}’ from ‘<brace-enclosed initializer list>’ to ‘S’
S x = { .member = S::S::E1 };
这些似乎遵循不同的规则。这是怎么回事?
接下来,让我们再尝试一点虐。这是整个程序:
#include <iostream>
struct S {
S() { std::cout << "made an S\n"; }
enum E { E1, E2 } member;
};
int main() {
std::cout << S::S::S::S::S::E1 << std::endl;
#ifdef DECL
S::S::S var;
#endif
return 0;
}
此代码在两个编译器中编译(没有 -DDECL
):
$ clang++-3.9 -std=c++11 -Wall -O namespace.cc
$ ./a.out
0
$ g++ -Wall -std=c++11 -O namespace.cc
$ ./a.out
0
(没有 S
在这里构造,尽管 clang 为早期代码中的变量 member
初始值设定项发出了提示。)在 main
中启用变量>,尽管如此,会导致 g++ 失败,但不会导致 clang:
$ clang++-3.9 -std=c++11 -DDECL -Wall -O namespace.cc
$ ./a.out
0
made an S
$ g++ -std=c++11 -DDECL -Wall -O namespace.cc
namespace.cc: In function ‘int main()’:
namespace.cc:11:3: error: ‘S::S’ names the constructor, not the type
S::S::S var;
^
namespace.cc:11:11: error: expected ‘;’ before ‘var’
S::S::S var;
^
namespace.cc:11:14: error: statement cannot resolve address of overloaded function
S::S::S var;
^
哪个编译器是正确的,为什么?这个“过度限定”名称的规则究竟是什么?