2013-08-20 13 views
12

Wpadłem na to dziwne zachowanie podczas testowania, czy typename jest wymagane przez klang. Zarówno clang, jak i gcc akceptują ten kod, podczas gdy msvc go odrzuca.Czy typename można pominąć w specyfikatorze typu definicji elementu końcowego?

template<class T1> 
struct A 
{ 
    template<class T2> 
    struct B 
    { 
     static B f; 
     static typename A<T2>::template B<T1> g; 
    }; 
}; 

template<class T1> 
template<class T2> 
typename A<T2>::template B<T1> // ok, typename/template required 
    A<T1>::B<T2>::g; 

template<class T1> 
template<class T2> 
A<T1>::B<T2> // clang/gcc accept, msvc rejects missing typename 
    A<T1>::B<T2>::f; 

Ogólnie kwalifikowaną id A<T1>::B<T2> (gdzie A<T1> to nazwa zależna) powinny być napisane typename A<T1>::template B<T2>. Czy zachowanie gcc/clang jest niepoprawne, czy jest wyjątek od ogólnej reguły (cytowanej poniżej) w tym konkretnym przypadku?

Można argumentować, że A<T1> nie jest nazwą zależną, lub że B<T2> odnosi się do członka bieżącej instancji. Jednak w momencie analizowania specyfikatora typu nie można stwierdzić, że bieżąca instancja jest A<T1>. Wydaje się problematyczne wymaganie implementacji, aby odgadnąć, że A<T1> jest obecną instancją.

14,6 rozdzielczości nazwa [temp.res]

nazwa używana w deklaracji lub definicji szablonu i że jest zależny od szablonu-parametru jest zakłada nie nazwać typ, chyba że zastosowanie znajdzie wyszukiwanie nazw nazwa typu lub nazwa jest kwalifikowana według słowa kluczowego typename.

14,2 Nazwy kierunkach szablonu [temp.names]

Gdy pojawi się nazwa specjalizacji szablonu człon po . lub -> w przyrostkiem ekspresji lub po zagnieżdżonej-NAME specyfikatora wykwalifikowanego-id , a wyrażenie obiektu lub wskaźnika wyrażeń postfiksów lub specyfikatora nazw zagnieżdżonych w kwalifikowanym id zależy od parametru szablonu (14.6.2), ale nie odnosi się do członka bieżącej instancji (14.6. 2.1), nazwa szablonu elementu członkowskiego musi być poprzedzona prefiksem szablonu słowa kluczowego . W przeciwnym razie przyjmuje się, że nazwa nie jest szablonem.

celu dalszego zbadania, co robi tutaj dzyń, próbowałem też to:

template<class T1> 
struct C 
{ 
    template<class T2> 
    struct D 
    { 
     static typename A<T1>::template B<T2> f; 
     static typename A<T1>::template B<T2> g; 
    }; 
}; 

template<class T1> 
template<class T2> 
typename A<T1>::template B<T2> // ok, typename/template required 
    C<T1>::D<T2>::f; 

template<class T1> 
template<class T2> 
A<T1>::B<T2> // clang rejects with incorrect error 
    C<T1>::D<T2>::g; 

Clang daje error: redefinition of 'g' with a different type, ale rodzaj g rzeczywiście pasuje do deklaracji.

Zamiast tego oczekuję diagnostyki sugerującej użycie typename lub template.

Daje to hipotezę, że zachowanie klangów w pierwszym przykładzie jest niezamierzone.

+0

Osobiście dodać 'typename' ... ale nie mają dążenie do wykopania się w standardzie właśnie teraz :) –

+0

@dribeas Bez obaw;). Musisz już mieć dość tych wszystkich pytań prawnika językowego! – willj

+6

Niezależnie od tego, która z nich jest dobra lub zła, zasługujesz na awans tylko dla znalezienia * dowolnego * kodu, który gcc i clang akceptują, ale VC++ odrzuca na podstawie brakującego 'typename'. –

Odpowiedz

1

clang i gcc są poprawne.

Kompilator zna A<T1>::B<T2> odnosi się do typu, a B<T2> jest szablonem, a A<T1>::B<T2>::f jest członkiem bieżącej instancji. Dlatego słowa kluczowe typename i template nie są konieczne.

Od 14.6.2.1P4:

nazwa jest członkiem obecnego instancji jeśli jest

Wykwalifikowany ID, w którym zagnieżdżone nazwa-specyfikator dotyczy obecnego instancji oraz, gdy ogląda się odnosi co najmniej jednego członka obecnego instancji

A<T1>::B<T2> jest kwalifikowana ID i A<T1>:: jest zagnieżdżony nazw specyfikator który odnosi się do obecnego instancji. Wiemy, że A<T1>:: odnosi się do bieżącej instancji z 14.6.2.1p1:

Nazwa odnosi się do bieżącej instancji, jeżeli jest

- w definicja podstawowy klasa szablon lub członkiem z podstawowej klasy matrycy, nazwę matrycy klasy, po czym liście argumentów matrycy podstawowego matrycy (jak opisano poniżej) zamkniętego w <> (lub równoważnego matrycy ali jako specjalizacji),

w kodzie, mamy definicję członek podstawowej klasy szablonu, czyli A<T1>::B<T2>::f i A<T1> to nazwa szablonu klasy, a następnie z listy szablon argumentu podstawowego szablonu.

W swoim pytaniu mówisz: However, at the point of parsing the type-specifier it's not possible to know that the current instantiation is A<T1>. Nie mogę tego jednak zrobić, ponieważ nazwa A<T1> odnosi się do obecnej instancji, jak podano powyżej.

+0

Reguły, które wymagają 'typename' (i' template'), umożliwiają analizatorowi sprawdzanie, czy nazwa zależna jest typem czy szablonem. Parser przechodzi przez strumień tokenów i musi podjąć decyzję, czy nazwa jest typem (lub szablonem) w punkcie, w którym napotkano token. Aby zdecydować, czy 'A :: B' nazywa szablon klasy bez słowa kluczowego' typename', parser musiałby szukać wyprzedzającej (potencjalnie nieograniczonej) liczby tokenów, aby odkryć, że 'A ' jest bieżącą instancją. – willj

+0

@willj: Pierwsza część komentarza jest poprawna, a druga nie. Niektóre formy nazwy identyfikują obecną instancję. W tym przypadku 'A ' i ':: A ' oba nazywają bieżącą instancję. Kompilator identyfikuje bieżącą instancję za pomocą składni, patrz 14.6.2.1p3 dla przykładów. –

+0

Zobacz [ten przykład] (http://coliru.stacked-crooked.com/view?id=3fe1c0107d63f27f28792d7678c32b3a-25dabfc2c190f5ef027f31d968947336) oraz komunikaty o błędach. Kompilator ** wie ** 'A :: B' nazywa szablon klasy, ponieważ już go sprawdził. –

1

MSVC jest poprawny.

Moje czytanie normy C++ 11 sugeruje, że wymagany jest typename.

Bez słowa kluczowego typename przyjmuje się, że nazwa zależna nie jest nazwą typu.

14,6 rozdzielczości nazwa [temp.res]

2) nazwa używana w deklaracji lub definicji szablonu i że jest zależny od szablonu-parametru jest zakłada nie nazwać typ, chyba że zastosowanie wyszukiwanie nazw znajduje nazwę typu lub nazwa jest kwalifikowana według słowa kluczowego nazwa_typu.

3) Jeżeli kwalifikacje ID ma odnosić się do rodzaju, który nie należy do bieżącej instancji i swojej osadzonej-NAME specyfikatora odnosi się do typu zależnego, musi być poprzedzony typeName słów kluczowych

7) w definicji szablonu klasy lub w definicji członka szablonu klasy po declarator-id The typename Hasło nie jest wymagane, gdy odnosi się do nazwy wcześniej zadeklarowane członek szablonu klasy, który deklaruje typ.[Uwaga: nazwy te można znaleźć za pomocą nazwę niekwalifikowaną odnośnika, klasy członek odnośnika do bieżącego instancji lub członkiem klasy dostępu wyrażenie przeglądowej gdy rodzaj ekspresji obiektu jest obecny instancji

14.6.2.1 Dependent rodzaje [temp.dep.type]

Nazwa dotyczy obecnego instancji jeśli jest

  • w definicji klasy głównej matrycy lub członkiem pierwotnego Klasa szablon nazwa szablonu klasy następnie szablon listy argumentu pierwotnego wzoru (jak opisano poniżej) zamknięty w <>

Gdy A<T1> jest stosowany w definicji członek A , odnosi się do bieżącej instancji . Podczas analizowania definicji f, nazwa typu kwalifikowana przez A<T1>:: może być znaleziona przez analizę nazwy elementu klasy klasy w bieżącej instancji.

Jednak, gdy analizator składni C++ napotka A<T1> w typie zwracania definicji funkcji składowej - przed identyfikatorem-deklaratora - nie napotkał jeszcze nazwy klasy zamykającej. Analizator składni nie może określić, czy w tym punkcie A odnosi się do klasy otaczającej.

Z tego powodu - niezależnie od tego, czy A<T1> nazywa bieżącą instancję, czy nie, standard nie zezwala na pominięcie typename w definicji elementu szablonu klasy przed identyfikatorem-identyfikatorem.

Ten example przez Vaughn Cato dowodzi, że zachowanie Clang/GCC jest niespójna i wymaga typename w podobny scenariusz:

template <typename T> 
struct A { 
    typedef int X; 
    X f(); 
}; 

template <typename T> 
A<T>::X A<T>::f() // error: missing 'typename' 
{ 
} 
Powiązane problemy