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.
Osobiście dodać 'typename' ... ale nie mają dążenie do wykopania się w standardzie właśnie teraz :) –
@dribeas Bez obaw;). Musisz już mieć dość tych wszystkich pytań prawnika językowego! – willj
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'. –