Collisione dello spazio dei nomi C ++ nel costruttore di copie


33

Ho il codice seguente:

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

struct Foo {
    int b;
};

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

I compilatori C ++ si lamentano di "c = foo.b" perché A :: Foo non ha un membro di nome b. Se cambio il tipo di parametro Bar con :: Foo funziona.

La mia domanda è qual è il razionale dietro questo comportamento (suppongo che abbia a che fare con il fatto che l'eredità fa entrare Bar nello spazio dei nomi A ma non riesco a trovare alcuna documentazione a supporto di questa teoria.


8
Penso che sia correlato alla ricerca dipendente dall'argomento. Ho taggato "avvocato della lingua" perché penso che tu stia cercando risposte che fanno riferimento allo standard linguistico. E un'ottima prima domanda! Ne vale la pena.
Bathsheba,

Non entra nello spazio dei nomi A, che puoi vedere se lasci Barereditare da un'altra struttura A. Quindi non c'è ambiguità. E 'più come l'eredità aggiunge tutto dal A::Fooal Barcompresa la risoluzione di Fooa A::Foo. Mi dispiace, non posso davvero esprimerlo in modo più preciso.
n314159,

@Bathsheba Intendi la ricerca del nome dipendente dal tipo di argomento per trovare nomi di funzione (o nomi di modelli di funzione) o nomi dipendenti in modelli?
curioso

Risposte:


22

Ogni classe ha il suo nome iniettato come membro. Quindi puoi nominare A::Foo::Foo. Questo è chiamato il nome della classe iniettata.

[classe]

2 Un nome di classe viene inserito nell'ambito in cui viene dichiarato immediatamente dopo la visualizzazione del nome di classe. Il nome della classe viene anche inserito nell'ambito della classe stessa; questo è noto come il nome della classe iniettata. Ai fini del controllo dell'accesso, il nome della classe iniettata viene trattato come se fosse un nome di membro pubblico.

[Basic.lookup]

3 Il nome della classe iniettata di una classe è anche considerato membro di quella classe ai fini del nascondimento e della ricerca del nome.

Poiché la ricerca di nomi non qualificati del tipo di argomento inizia nell'ambito della classe Bar, continuerà nell'ambito della sua classe base per tenere conto di qualsiasi membro lì. E troverà A::Foo::Foocome nome del tipo.

Se si desidera utilizzare il nome del tipo globale, è sufficiente qualificarlo in base allo spazio dei nomi (globale) circostante.

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

Che sta effettuando una ricerca completa in un ambito in cui il nome della classe iniettata non viene visualizzato.

Per un follow-up "perché" domanda vedi


5
@TedLyngmo - L'ADL si verifica con chiamate di funzione, nulla di rilevante in quei passaggi specifici.
StoryTeller - Unslander Monica,

Oki, stavo leggendo e non ne ero sicuro. Grazie!
Ted Lyngmo,

3
Questo porta al molto divertente, struct Bar:: A::Foo::Foo::Foo::Foo::Foo {}; ma ci sono contesti in cui A::Foo::Foodesigna il costruttore e quindi non puoi continuare ad aggiungere quanti Foone vuoi. Questo è simile (ma con un meccanismo completamente diverso) per il fatto che si può chiamare una funzione fin questo modo: (************f)().
AProgrammer,

@AProgrammer - Infatti. E si possono costruire esempi ancora più divertenti .
StoryTeller - Unslander Monica,

Questa risposta spiega certamente il "cosa". Può essere migliorato per aggiungere il "perché"? Come in, qual è lo scopo di questa regola? Quali casi d'uso migliora o rende possibile?
davidbak,

2

Non è una risposta completa, solo il codice che mostra (poiché si compila) che Barnon inserisce il namespace A. Si può vedere che quando si eredita da A::Foo1non vi è alcun problema con l'ambiguità di Foocui sarebbe diverso se questa eredità lascia Barentrare 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;
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.