Mi sono imbattuto in questo strano comportamento durante il test se è richiesto o meno typename
da clang. Sia clang che gcc accettano questo codice mentre msvc lo rifiuta.È possibile omettere il typename nello specificatore di tipo di una definizione di membro fuori linea?
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;
In generale, un qualificato-id A<T1>::B<T2>
(dove A<T1>
è un nome dipendente) dovrebbe essere scritto typename A<T1>::template B<T2>
. Il comportamento di gcc/clang è errato o c'è un'eccezione alla regola generale (citata sotto) in questo caso particolare?
Si potrebbe sostenere che A<T1>
non è un nome dipendente o che B<T2>
fa riferimento a un membro dell'istanza corrente. Tuttavia, al momento di analizzare l'identificatore del tipo non è possibile sapere che l'istanza corrente è A<T1>
. Sembra problematico richiedere l'implementazione per indovinare che A<T1>
è l'istanza corrente.
14,6 risoluzione dei nomi [temp.res]
un nome usato in una dichiarazione modello o definizione e che dipende da un modello-parametro è non assunto per citarne tipo a meno che il nome applicabile ricerca trova un nome di tipo o il nome è qualificato dalla parola chiave typename.
14.2 Nomi di specializzazioni template [temp.names]
Quando il nome di una specializzazione template membro appare dopo
.
o->
in un suffisso-espressione o dopo un nested-nome-identificatore in un qualificato-id e l'espressione dell'oggetto o del puntatore dell'espressione postfisso o dello specificatore di nome nidificato nell'ID qualificato dipende da un parametro del modello (14.6.2) ma non fa riferimento a un membro dell'istanza corrente (14.6. 2.1), il nome del modello membro deve essere preceduto dal modello della parola chiave . Altrimenti si suppone che il nome indichi un non-modello.
Per indagare ulteriormente ciò che clang sta facendo qui, ho anche provato questo:
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 dà error: redefinition of 'g' with a different type
, ma il tipo di g
realtà corrisponda alla dichiarazione.
Mi piacerebbe invece vedere una diagnostica che suggerisce l'uso di typename
o template
.
Ciò dà credito all'ipotesi che il comportamento di clang nel primo esempio non sia intenzionale.
io personalmente sarebbe aggiungere il 'typename' ... ma non hanno l'unità per scavare nello standard proprio ora :) –
@dribeas Nessun problema;). Devi essere stanco di tutte queste domande di avvocato linguistico ormai! – willj
Indipendentemente dal fatto che sia giusto o sbagliato, ti meriti un upvote solo per trovare * qualsiasi * codice accettato da gcc e clang, ma VC++ rifiuta sulla base di un 'typename 'mancante. –