我遇到了一些这样的代码:

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类型的名为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) {
                     ^

可以使用冗余的类限定符来引用该类型,这似乎很奇怪。

同样,VS11和clang/gcc对A::A(i)的解析似乎有所不同。如果我执行A::A(b) clang和gcc,则使用默认构造函数创建b类型的变量A。 VS11错误指出b是未知标识符。 VS11似乎使用构造函数A::A(i)(以A作为参数)将A::A(int)解析为临时i的创建。消除了多余的限定符后,VS会像clang和gcc一样将源解析为变量声明,并且会产生类似于隐藏变量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在其他变量声明变量的地方构造了一个临时变量。当clang和gcc将B b(A::A(i));解析为最令人讨厌的解析时,情况甚至可能变得更糟,但是VS认为这是使用初始化程序声明了b类型的B变量。如此严重的差异还有很多吗?
  • 显然,在可移植代码中应避免多余的限定符。有什么好的方法可以防止使用此构造?
  • 最佳答案

    尽管这种现象很可能归因于类名注入(inject),如ephemient的回答所述,但对于此特定示例,它早已被C++语言禁止使用。

    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#147

    需要组合A::A来引用类构造函数,而不是类注入(inject)名称。符合要求的编译器应将A::A(i)解释为涉及构造函数名称的非法(因此无意义)表达式。举个例子,Comeau编译器将因此而拒绝编译您的代码。

    显然,VC11继续将A::A视为对注入(inject)的类名的引用。有趣的是,我在VS2005中没有观察到此问题。

    早在A::A被解释为引用注入(inject)的名称的那一天,就可以将A对象声明为

    A::A::A::A::A::A a;
    

    依此类推,使用任意数量的A。但是现在不行了。令人惊讶的是,ideone使用的GCC版本(4.3.4?)仍然遭受此问题的困扰

    http://ideone.com/OkR0F

    您可以在您的VC11版本中尝试一下,看看是否允许这样做。

    关于c++ - 为什么允许冗余的类名限定符?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11423380/

    10-11 00:43