C ++ - Namespace-Kollision im Kopierkonstruktor

33

Ich habe folgenden Code:

namespace A {
    struct Foo {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};

C ++ - Compiler beschweren sich bei "c = foo.b", weil A :: Foo kein Mitglied namens b hat. Wenn ich den Typ des Bar-Parameters mit :: Foo ändere, funktioniert es.

Meine Frage ist, was der Grund für dieses Verhalten ist (ich nehme an, es hat damit zu tun, dass die Vererbung Bar dazu bringt, in den A-Namespace einzutreten, aber ich kann keine Dokumentation finden, die diese Theorie unterstützt.

Vincent Le Ligeour
quelle
8
Ich denke, es hängt mit der argumentabhängigen Suche zusammen. Ich habe "Sprachanwalt" markiert, da ich denke, dass Sie nach Antworten suchen, die auf den Sprachstandard verweisen. Und eine sehr gute erste Frage! Das alles lohnt sich.
Bathseba
Es wird kein Namespace eingegeben A, den Sie sehen können, wenn Sie Barvon einer anderen Struktur in erben lassen A. Dann gibt es keine Mehrdeutigkeit. Es ist eher so, als würde die Vererbung alles von A::Foobis Bareinschließlich der Auflösung von Foobis hinzufügen A::Foo. Entschuldigung, ich kann es nicht genauer ausdrücken.
n314159
@Bathsheba Meinen Sie die Suche nach abhängigen Namen vom Argumenttyp, um Funktionsnamen (oder Namen von Funktionsvorlagen) oder abhängige Namen in Vorlagen zu finden?
Neugieriger

Antworten:

22

Jede Klasse hat ihren Namen als Mitglied. So können Sie benennen A::Foo::Foo. Dies wird als Name der injizierten Klasse bezeichnet.

[Klasse]

2 Ein Klassenname wird in den Bereich eingefügt, in dem er unmittelbar nach dem Anzeigen des Klassennamens deklariert wird. Der Klassenname wird auch in den Bereich der Klasse selbst eingefügt. Dies ist als Name der injizierten Klasse bekannt. Für die Zugriffsprüfung wird der Name der injizierten Klasse so behandelt, als wäre er ein öffentlicher Mitgliedsname.

[basic.lookup]

3 Der Name der injizierten Klasse einer Klasse wird auch zum Ausblenden und Nachschlagen von Namen als Mitglied dieser Klasse betrachtet.

Da die Suche nach unqualifizierten Namen des Argumenttyps im Bereich der Klasse beginnt Bar, wird sie im Bereich ihrer Basisklasse fortgesetzt, um dort ein Mitglied zu berücksichtigen. Und es wird A::Foo::Fooals Typname gefunden.

Wenn Sie den globalen Typnamen verwenden möchten, qualifizieren Sie ihn einfach anhand seines umgebenden (globalen) Namespace.

Bar(::Foo foo) {
    c = foo.b;
}

Dies führt eine vollständig qualifizierte Suche in einem Bereich durch, in dem der Name der injizierten Klasse nicht angezeigt wird.

Für eine Folge "Warum" Frage siehe

Geschichtenerzähler - Unslander Monica
quelle
5
@TedLyngmo - ADL tritt bei Funktionsaufrufen auf, die in diesen spezifischen Passagen nicht relevant sind.
Geschichtenerzähler - Unslander Monica
Oki, ich habe gelesen und war mir nicht sicher. Vielen Dank!
Ted Lyngmo
3
Dies führt zu sehr amüsanten, struct Bar:: A::Foo::Foo::Foo::Foo::Foo {}; aber es gibt Kontexte, in denen A::Foo::Fooder Konstruktor bezeichnet wird, und daher können Sie nicht so viele hinzufügen, Foowie Sie möchten. Dies ähnelt (aber mit einem völlig anderen Mechanismus) der Tatsache, dass Sie eine Funktion folgendermaßen aufrufen fkönnen : (************f)().
AProgrammer
@ AProgrammer - In der Tat. Und man kann noch amüsantere Beispiele konstruieren .
Geschichtenerzähler - Unslander Monica
Diese Antwort erklärt sicherlich das "Was". Kann es verbessert werden, das "Warum" hinzuzufügen? Was ist der Zweck dieser Regel? Welche Anwendungsfälle verbessert oder ermöglicht es?
Davidbak
2

Keine vollständige Antwort, nur Code, der anzeigt (da er kompiliert wird), dass Barder nicht eingegeben wird namespace A. Sie können sehen, dass es beim Erben von A::Foo1kein Problem gibt, dessen Mehrdeutigkeit Fooanders wäre, wenn diese Vererbung Bareintreten würde A.

namespace A {
    struct Foo {
        int a;
    };

    struct Foo1 {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo1 {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};
n314159
quelle