我遇到了一些这样的代码:
struct A {
A() {}
A(int) {}
};
struct B : A {
void init(int i);
};
void B::init(int i) {
A::A(i); // what is this?
}
int main() {
B b;
b.init(2);
}
这使用 VC11 beta 编译和运行,没有 /W4 的错误或警告。
明显的意图是调用 B::init 来重新初始化 B 的 A 基子对象。我相信它实际上解析为一个名为i
type的新变量的变量声明A
。使用 clang 编译会产生诊断:
ConsoleApplication1.cpp:11:14: warning: declaration shadows a local variable
A::A(i);
^
ConsoleApplication1.cpp:10:22: note: previous declaration is here
void B::init(int i) {
^
ConsoleApplication1.cpp:11:14: error: redefinition of 'i' with a different type
A::A(i);
^
ConsoleApplication1.cpp:10:22: note: previous definition is here
void B::init(int i) {
^
可以用多余的类限定来引用该类型似乎很奇怪。
此外,A::A(i)
VS11 和 clang/gcc 的解析方式似乎有所不同。如果我使用默认构造函数A::A(b)
创建 clang 和 gccb
类型的变量。A
VS11 错误说b
是未知标识符。VS11 似乎解析为使用构造函数作为参数A::A(i)
创建临时。当冗余限定符被消除时,VS 像 clang 和 gcc 一样将源解析为变量声明,并产生类似的关于隐藏变量的错误。A
A::A(int)
i
i
这种解析上的差异解释了为什么 VS11 会阻塞多个额外的限定符;A::A::A::A(i)
,以及为什么,鉴于 clang 和 gcc 可以接受一个额外的限定符,任何多于一个的数字与一个额外的结果相同。
这是另一个在不同上下文中使用冗余限定符的示例。所有编译器似乎都将其解析为临时结构:
class Foo {};
void bar(Foo const &) {}
int main() {
bar(Foo::Foo());
}
- 为什么完全允许冗余限定符?
- 在某些情况下可以引用构造函数,例如继承构造函数的语法 (
class D : B { using B::B; };
),但 VS 似乎允许在任何地方使用它。VS 错了吗,clang 和 gcc 在如何解析冗余限定符方面是否正确? - 我知道 VS 在标准合规性方面仍然有点落后,但我确实发现现代、积极开发的编译器可能如此不同,在这种情况下将冗余限定符解析为构造函数的名称(即使构造函数没有名称)与将冗余限定符简单地解析为类型,导致 VS 在其他人声明变量的地方构造一个临时的。
B b(A::A(i));
在被 clang 和 gcc 解析为最令人头疼的解析时,情况可能会变得更糟,但 VS 将其视为使用初始化程序声明b
类型变量。B
这么严重的分歧还有很多吗? - 显然,在可移植代码中应该避免冗余限定符。有没有防止使用这种构造的好方法?