2012-10-17 4 views
8

Cercando di compilare il seguente codice su diversi compilatori mi dà due risultati diversi:Un membro di una classe può avere lo stesso nome del suo tipo (un'altra classe)?

struct S{}; 
struct T{S S;}; 
int main(){} 

Come si può vedere, all'interno T, ho un oggetto chiamato lo stesso della classe precedentemente definita S.


In GCC 4.7.2, I get the following error appartenente alla dichiarazione S S; all'interno T:

error: declaration of 'S T::S' [-fpermissive]
error: changes meaning of 'S' from 'struct S' [-fpermissive]

Tuttavia, spostandolo fuori della classe (o in main) works fine:

struct S{}; 
S S; 
int main(){} 

Che cosa significa esattamente per l'errore che mi sta dando?


In Visual Studio 2012, l'intero processo viene compilato e eseguito senza errori. Incollarlo in this Clang 3.0 compiler non mi dà errori pure.

Quale è giusto? Posso davvero farlo o no?

+0

Ah, capisco - ho letto male la diagnostica. – ildjarn

+1

@ildjarn, è una bandiera piuttosto strana. Sembra funzionare al contrario. Normalmente, la bandiera responsabile di un avvertimento appare tra parentesi quadre. – chris

+2

Proprio no. Qual e il punto? Confuso? Nota che dopo aver fatto ciò, non puoi più fare riferimento al tipo 'S' nelle funzioni membro senza qualificare esplicitamente il namespace ... –

risposta

14

gcc è corretto, dal [Scope 3.3.7 Classe]

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

Si noti tuttavia che no diagnostic is required, in modo che tutti i compilatori sono conformi.

Il motivo è dovuto al modo in cui funziona lo scope di classe. Quando si scrive S S;S è visibile all'interno della classe intera e cambia il significato quando si utilizza S.

struct S{}; 
struct T{ 
    void foo() 
    { 
     S myS; // Not possible anymore because S refers to local S 
    } 
    S S; 
}; 
+1

La logica, IIRC, è quella di consentire la definizione delle funzioni dei membri della classe all'interno della classe. La ricerca del nome al loro interno sarebbe funky se il significato di un nome cambia all'interno di una classe. (È già abbastanza difficile come-è). – MSalters

+0

Lo stesso esempio funziona perfettamente con la semantica corretta in C#. Il 's'member è anche utilizzabile con la semantica corretta. C# è in grado di distinguere il contesto in cui viene usato 'S' e non è chiaro il motivo per cui i compilatori C++ non dovrebbero essere in grado di fare lo stesso. – ceztko

6

Questo codice è mal formato, non è richiesta alcuna diagnostica. Come dice la diagnostica, se una dichiarazione utilizza un nome e il nome ha un significato diverso da quello che avrebbe quando viene visualizzato alla fine della definizione della classe, il programma non è corretto, non è richiesta alcuna diagnostica.

+0

Un altro giorno in cui mi sto migliorando! +1 –

6

@JesseGood fornire una risposta completa, ma se si vuole veramente fare questo senza alcun errore, è possibile utilizzare il nome completo del tipo e che funzionerà come segue:

struct S {}; 
struct T { ::S S; }; 
int main() {return 0;} 

No non c'è errore, dal S nella tua classe è T::S e il suo tipo è ::S!