2012-10-17 17 views
8

Próbując skompilować następujący kod na różnych kompilatorów daje mi dwa różne wyniki:Czy członek klasy może mieć taką samą nazwę jak jej typ (inna klasa)?

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

Jak widać, wewnątrz T, mam obiekt nazwany tak samo jak wcześniej zdefiniowanej klasy S.


Na GCC 4.7.2, I get the following error dotyczące deklaracji S S; wewnątrz T:

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

Jednakże, przesuwając go na zewnątrz klasy (lub do main) works fine:

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

Co dokładnie oznacza błąd, który mi daje?


W Visual Studio 2012 całość się kompiluje i działa bez żadnych błędów. Wklejenie go do this Clang 3.0 compiler również nie powoduje żadnych błędów.

Co jest właściwe? Czy mogę to zrobić, czy nie?

+0

Ach, rozumiem - źle odczytałem diagnostykę. – ildjarn

+1

@ildjarn, To raczej dziwna flaga. Wydaje się działać odwrotnie. Zwykle flaga odpowiedzialna za ostrzeżenie pojawia się w nawiasach kwadratowych. – chris

+2

Po prostu nie rób tego. Jaki jest sens? Dezorientować? Zauważ, że po wykonaniu tej czynności nie możesz już odwoływać się do typu 'S' w funkcjach składowych bez jawnego zakwalifikowania przestrzeni nazw ... –

Odpowiedz

14

gcc jest poprawna, z [3.3.7] Klasy Zakres

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.

jednak pamiętać, że no diagnostic is required, więc wszystkie kompilatory są zgodne.

Powodem jest to, jak działa zakres klasy. Podczas pisania S S; jest widoczny w klasie cały i zmienia znaczenie, gdy używasz S.

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

Uzasadnieniem IIRC jest umożliwienie definiowania funkcji klasy w klasie. Wyszukiwanie nazwisk w nich byłoby ciekawe, gdyby znaczenie nazwy zmieniło się w klasie. (Jest już wystarczająco twardy jak jest). – MSalters

+0

Ten sam przykład działa doskonale z poprawną semantyką w języku C#. 'S'member jest również użyteczny z poprawną semantyką. C# jest w stanie rozróżnić kontekst, w którym 'S' jest używany i nie jest jasne, dlaczego kompilatory C++ nie powinny być w stanie zrobić tego samego. – ceztko

6

Ten kod jest niepoprawny, nie wymaga diagnostyki. Podobnie jak w przypadku diagnostyki, jeśli deklaracja używa nazwy, a nazwa ma inne znaczenie niż w przypadku określenia na końcu definicji klasy, program jest nieprawidłowy, nie wymaga diagnostyki.

+0

Kolejny dzień, w którym ulepszam siebie! +1 –

6

@JesseGood zapewnić pełną odpowiedź, ale jeśli naprawdę chcesz to zrobić bez żadnego błędu, można użyć pełnej nazwy typu i będzie działać następująco:

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

Nie Nie ma błąd, ponieważ S w twojej klasie to T::S, a jego typ to ::S!

Powiązane problemy