2016-07-04 21 views
26

vedere il seguente codice diUn comportamento strano di dichiarazione using

struct A { using type = int; }; 
struct B : private A {}; 
struct C : B { using base_type = A; }; 

Tutti gcc 6.1, clang 3.8, e msvc Aggiornamento 2015 3 rifiutano di compilare questo, come A non è un nome accessibili all'interno C dal A è una base privata di B. Sembra che gcc pensi che A in using base_type = A si riferisca al costruttore predefinito di A. msvc e clang non sembrano.

Forse l'errore di compilazione è dovuto alla iniezione di nomi innescato da eredità (perché la modifica using base_type = A in using base_type = ::A fanno tutti i compilatori funzionano bene), ma voglio sapere se questo errore strano è ciò che dice lo standard.

Più concretamente,

  1. Come ho capito, non come A::type, A è solo un nome di classe (anche se interpreta male gcc come un nome di funzione) che viene introdotto a Cnon all'internoAB. Perché questo nome è considerato privato per B?
  2. Questo errore di compilazione può essere considerato un bug o è un caso limite delle specifiche dello standard?
+1

Suppongo che ciò sia dovuto al modo in cui il nome cerca "A' dentro" C ".Per prima cosa controlla se è stato dichiarato qualcosa con un nome 'A' nell'ambito di' C' prima di 'using'. Dal momento che non ne trova uno, lo sta controllando nell'ambito di 'B' dato che è la classe Base. E nel caso in cui non trovi l'estensione 'A' in' B', si troverà nello 'spazio dei nomi globale'. Ma in qualche modo "l'ereditarietà privata" di "A" di "B" viene fermata alla seconda ricerca all'interno dello scope di "B". Dal momento che funziona con il nome 'fully qualified', questo mi fa pensare che il vero problema debba essere sulla stessa linea. – Arunmu

+4

http://eel.is/c++draft/class.access.spec#5 sembra rilevante –

+0

@PiotrSkotnicki Grazie, risponde direttamente alla domanda. Ma puoi darmi il razionale dietro questa regola? –

risposta

28

Secondo la regola di unqualified name lookup:

(sottolineatura mia)

Per un nome non qualificato, che è un nome che non appare a destra di un operatore di risoluzione dell'ambito :: , la ricerca dei nomi esamina gli ambiti come descritto di seguito, finché non trova almeno una dichiarazione di qualsiasi tipo, , quando la ricerca si interrompe e non vengono esaminati ulteriori ambiti.

Quindi il nome A verrà trovato prima nell'ambito della classe base, il nome nello spazio dei nomi globale non verrà considerato qui. Successivamente, viene eseguito il controllo di accesso corretto e quindi la compilazione non è riuscita.

E ::A specifica il nome nell'ambito globale e risolve il problema, rendendolo un qualified name lookup.

2

Distacco il mio commento come risposta (sembra come una risposta più di un commento):

Sto indovinando questo è dovuto al modo in cui la ricerca dei nomi per A all'interno C opere. Prima di utilizzare, controlla prima di trovare se qualcosa è stato dichiarato con il nome A nell'ambito di C. Dal momento che non ne trova uno, lo controlla nell'ambito di B poiché è la classe Base. E nel caso non trova l'ambito A in Bs, verrà visualizzato nello global namespace. Ma in qualche modo l'ereditarietà di A da B viene interrotta alla seconda ricerca, all'interno dello scope di B. Dal momento che funziona con il nome fully qualified, questo mi fa pensare che il vero problema deve essere sulla stessa linea.