Dlaczego dozwolone są nadmiarowe kwalifikatory nazw klas?

Natknąłem się na taki kod:

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);
}

Skompilował się i uruchomił przy użyciu VC11 beta bez błędów i ostrzeżeń przy / W4.

Widocznym celem jest wywołanie B :: init w celu ponownego zainicjowania podobiektu podstawowego B A. Uważam, że faktycznie analizuje jako deklarację zmiennej dla nowej zmiennej o nazwiei z typemA. Kompilowanie za pomocą clang powoduje diagnostykę:

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) {
                     ^

Ciekawe wydaje się, że do tego typu można odwołać się do zbędnych kwalifikacji klasowych.

Również,A::A(i) wydaje się być inaczej analizowany przez VS11 i clang / gcc. Jeśli zrobięA::A(b) clang i gcc tworzą zmiennąb typuA używając domyślnego konstruktora. Błędy VS11 w tym powiedzeniub jest nieznanym identyfikatorem. VS11 wydaje się parsowaćA::A(i) jako stworzenie tymczasowegoA za pomocą konstruktoraA::A(int) zi jako parametr. Po wyeliminowaniu nadmiarowego kwalifikatora VS analizuje źródło jako deklarację zmiennej, jak clang i gcc, i generuje podobny błąd dotyczący przesłaniania zmienneji.

Ta różnica w parsowaniu wyjaśnia, dlaczego VS11 zakrztusi się więcej niż jednym dodatkowym kwalifikatorem;A::A::A::A(i)i dlaczego, biorąc pod uwagę, że clang i gcc mogą akceptować jeden dodatkowy kwalifikator, dowolna liczba więcej niż jedna dodatkowa ma taki sam wynik jak jeden dodatkowy.

Oto kolejny przykład z nadmiarowymi kwalifikatorami w innym kontekście. Wszystkie kompilatory wydają się analizować to jako tymczasową konstrukcję:

class Foo {};

void bar(Foo const &) {}

int main() {
    bar(Foo::Foo());
}
Dlaczego dozwolone są w ogóle nadmiarowe kwalifikatory?Istnieją pewne konteksty, do których można odwoływać się do konstruktorów, takie jak składnia dziedziczenia konstruktorów (class D : B { using B::B; };) ale VS wydaje się pozwalać na to gdziekolwiek. Czy VS jest błędny i czy clang i gcc są dokładnie analizowane w ten sposób?Wiem, że VS jest wciąż dość spóźniony pod względem zgodności ze standardami, ale wydaje mi się nieco zaskakujące, że nowoczesne, aktywnie opracowane kompilatory mogą być tak rozbieżne, w tym przypadku rozwiązując nadmiarowy kwalifikator jako nazwę konstruktora (chociaż konstruktory nie mają nazw) a rozwiązywanie redundantnych kwalifikatorów po prostu do typu, co powoduje, że VS tworzy tymczasowy, w którym inne deklarują zmienną. Gdzie może być jeszcze gorzejB b(A::A(i)); jest analizowany przez clang i gcc jako najbardziej irytujący parsowanie, ale VS widzi to jako deklarację zmiennejb typuB z inicjatorem. Czy nadal jest wiele różnic, które są poważne?Oczywiste jest, że w przenośnym kodzie należy unikać zbędnych kwalifikatorów. Czy istnieje dobry sposób, aby zapobiec użyciu tego konstruktu?

questionAnswers(2)

yourAnswerToTheQuestion