2012-08-29 16 views
18

Kiedy skompilować następujący fragment z g++zmiany typedef czyli

template<class T> 
class A 
{}; 

template<class T> 
class B 
{ 
    public: 
     typedef A<T> A; 
}; 

kompilator mówi mi

error: declaration of ‘typedef class A<T> B<T>::A’ 
error: changes meaning of ‘A’ from ‘class A<T>’ 

Z drugiej strony, jeśli mogę zmienić typedef do

typedef ::A<T> A; 

wszystko kompiluje się dobrze z g++. Clang ++ 3.1 nie obchodzi w żaden sposób.

Dlaczego tak się dzieje? I jest drugim standardem zachowania?

+1

Musi to być poziom ostrzegawczy, który domyślnie pokazuje to jako błąd. To samo, co w przypadku funkcji, w której brakuje zwrotu, i można ją zgłosić jako błąd lub ostrzeżenie. Ogólnie, unikam deklarowania typu A jako A . To będzie mylące w późniejszym czasie. – Grzegorz

+0

Nie wiem, co standard mówi, ale cieszę się, że g ++ narzeka ... to po prostu głupie. –

+0

Myślę, że to nie jest ani głupie, ani mylące. Często napotykam na ten problem. Co do ostrzeżenia o konwersji błędów, nie podaję g ++ żadnych flag, jakie ostrzeżenia domyślnie konwertują na błędy? – foxcub

Odpowiedz

10

g ++ jest poprawny i zgodny ze standardem. W [3.3.7/1]:

konieczne jest n nazwy stosowane w klasie S odnosi się do tego samego zgłoszenia w kontekście kiedy ponownie oceniany w kompletnym zakresie S. nr diagnostyczny za naruszenie tej zasady.

Przed typedef, A przekazana ::A, jednak za pomocą typedef, teraz uczynić A odnoszą się do typedef co jest zabronione. Jednak od no diagnostic is required, klang jest również standardem zgodnym.

jogojapan's comment wyjaśnia przyczynę tej reguły. Take następujące zmiany do kodu:

template<class T> 
class A 
{}; 

template<class T> 
class B 
{ 
    public: 
     A a; // <-- What "A" is this referring to? 
     typedef  A<T>   A; 
}; 

Ze względu na sposób działania zakres klasy, A a; staje się niejednoznaczna.

+0

Co z drugim formularzem? Czy jest to również błąd, a g ++ po prostu go nie zgłasza? – foxcub

+3

@foxcub: W drugiej formie nie odwołujesz się do 'A', masz na myśli' :: A'. Drugi formularz jest poprawny. –

+0

@foxclub: Druga forma jest w porządku (jak wyjaśnia Kevin Ballard), ponieważ znaczenie słowa "A" się nie zmienia. –

1

dodam do odpowiedzi Jesse'ego o pozornie dziwne zachowanie GCC w kompilacji:

typedef A<T> A; 

vs

typedef ::A<T> A; 

Odnosi się to również do korzystania z oświadczenia, jak również w postaci:

using A = A<T>; 
using A = ::A<T>; 

To, co zdarza się w GCC, jest takie, że podczas kompilacji typedef/u Instrukcja sing deklarując B :: A, że symbol B :: A staje się ważnym kandydatem w samym słowie using. To znaczy. gdy mówi się, że using A = A<T>; lub typedef A<T> A; GCC uważa, że ​​zarówno kandydaci są ważni, jak i .

To dziwne zachowanie, ponieważ jak sugeruje twoje pytanie, nie oczekujesz, że nowy alias A stanie się prawidłowym kandydatem w samym typie, ale jak mówi również Jesse, wszystko zadeklarowane w klasie staje się widoczne dla wszystkiego innego wewnątrz klasy - iw tym przypadku najwyraźniej nawet sama deklaracja. Ten typ zachowania może zostać zaimplementowany w ten sposób, aby umożliwić definicje typu rekursywnego.

Rozwiązaniem, które znalazłeś, jest dokładne określenie GCC, do którego odwołujesz się w typie, a następnie już nie narzeka.