Penso che questo dipenda dalle regole nella sezione 14.6.2
dello standard. Fondamentalmente, penso che le regole siano errate nel richiedere di usare template
e typename
- una volta che si forma un'espressione che potrebbe essere potenzialmente dipendente, a volte sarà dichiarata tale in base alle regole, anche se un umano può chiaramente vedi che non è in realtà dipendente. Quindi, v'è una regola generale 14.6.2.2.1
che afferma
eccezione di quanto descritto di seguito, l'espressione è di tipo dipendente eventuale subespressione è di tipo-dipendente.
Quello che penso sta accadendo è che l'espressione fun2(d)
è dichiarato di essere a seconda del tipo secondo le regole, anche se che tipo è, infatti, lo stesso in ogni istanza di questo (primario) modello, come si e posso vedere - ecco perché è sorprendente che sia richiesto template
.
Sotto 14.6.2.1.4
in C++ 11 (o C++ 14) standard
Un nome è un membro dipendente dalla corrente istanziazione se è un membro della istanza corrente che , quando guardato in alto, si riferisce ad almeno un membro di una classe che è l'istanza corrente.
Ciò significa che, il nome è un nome fun2
dipendente, anche se fun2
non si riferisce a T
o qualsiasi cosa che dipende esplicitamente T
.
Così, quando si considera l'espressione che ha dato fun2(d).fun0<int>()
, e considerano il "accesso sottoespressione membro", vale a dire, fun2(d)
.
fun0<int>
- intuitivamente vogliamo dire che questo non dipende, come fun2(d)
è sempre di tipo bar
e fun0<int>
non dipendono neanche da T
. C'è regola 14.6.2.2.5
che afferma
Un'espressione accesso membro della classe (5.2.5) è dipendente dal tipo se l'espressione si riferisce ad un membro della corrente istanziazione e il tipo dell'organo riferimento dipende, o espressione di accesso membro della classe fa riferimento a un membro di una specializzazione sconosciuta.
Nessuna di queste condizioni si applica letteralmente, poiché bar
non è lo stesso tipo del istanziazione corrente (foo<T>
), e nessuno dei due è fun0<int>
un membro di una specializzazione sconosciuta del modello foo
. Questo è il motivo per cui l'espressione d.fun0<int>()
è ben formata.
Tuttavia, nota chiaramente che questa regola 14.6.2.2.5
viene dopo 14.6.2.2.1
che imposta il significato di tutta questa sezione:
eccezione di quanto descritto di seguito, l'espressione è di tipo dipendente eventuale subespressione è di tipo-dipendente.
Quindi se qualsiasi sottoespressione, come ad esempio fun2
, è formalmente "a seconda del tipo", che avvelena l'intera espressione, e fa sì che regole simili da applicare come se stavamo cercando fino membri di parametri di modello o specializzazioni sconosciuti, ecc . ecc
in particolare, la condizione type-dependent
significa che è necessario il prefisso template
, a causa della regola 14.2.4:
Quando il nome di una specializzazione template membro appare dopo .
o ->
in un postfix-expression o after a nested-specificatore di nome in un id qualificato e l'espressione dell'oggetto dell'espressione postfix è di tipo dipendente o lo identificatore nome-nidificato nell'ID qualificato si riferisce a un tipo dipendente, ma il nome non è un membro di l'istanza corrente (14.6.2.1), il nome del modello membro deve essere preceduto dal modello di parola chiave. In caso contrario, si assume che il nome indichi un modello diverso da modello.
Esempio:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
- esempio fine]
Ora molto concretamente:
Con [14.2.4], nell'espressione postfissa fun2(d)
.
, se l'espressione oggetto fun2(d)
è dipendente dal tipo, quindi è necessario utilizzare il prefisso template
per chiamare il modello membro.
Sotto [14.6.2.2.1], se fun2
è dipendente dal tipo allora che le forze fun2(d)
essere anche.
E sotto [14.6.2.1.4], dal momento che fun2
quando alzò gli occhi si riferisce ad un membro del template foo
di classe, che da sola è sufficiente per renderlo un membro dipendente l'istanza corrente.
io non hanno una tutto chiaro argomento qualsiasi delle regole che se un nome si riferisce ad un membro dipendente dalla corrente istanziazione, allora ciò implica che l'espressione corrispondente al nome è type-dependent
. .. e ho cercato un paio di volte adesso.
Tuttavia, questo punto di vista è sostenuto in @Johannes Schaub - litb highly up-voted (but simplified, and non-normative) exposition of the rules:
nomi dipendenti
Lo standard è un po 'poco chiaro su ciò che è esattamente un nome dipendente. In una lettura semplice (si sa, il principio della meno sorpresa), tutto ciò che definisce come un nome dipendente è il caso speciale per i nomi delle funzioni di seguito. Ma dal momento che T: x ha anche bisogno di essere guardato nel contesto dell'istanziazione, deve anche essere un nome dipendente (fortunatamente, a metà del C++ 14 il comitato ha iniziato a esaminare come risolvere questa definizione confusa) .
Per evitare questo problema, ho fatto ricorso a una semplice interpretazione del testo standard. Di tutti i costrutti che denotano tipi o espressioni dipendenti, un sottoinsieme di essi rappresenta nomi. Questi nomi sono quindi "nomi dipendenti". Un nome può assumere diverse forme: lo standard dice:
Un nome è un uso di un identificatore (2.11), ID funzione dell'operatore (13.5), ID funzione di conversione (12.3.2) o modello- id (14.2) che denota un'entità o un'etichetta (6.6.4, 6.1)
Un identificatore è solo una semplice sequenza di caratteri/cifre, mentre i due successivi sono l'operatore + e la forma del tipo di operatore. L'ultima forma è nome-modello. Tutti questi sono i nomi, e da un uso convenzionale nello Standard, un nome possono anche includere qualificazioni che dicono quello spazio dei nomi o classe di un nome deve essere guardato in.
sarebbe grande per avere una spiegazione più concreta di tale ultima parte.
Perché potresti specializzare 'fun2' per restituire qualcosa di diverso da' bar'. –
@AlanStokes In che modo specializzeresti 'fun2' in un modo che permette di cambiare il tipo di ritorno, mantenendo comunque' fun1' in giro? – hvd
@AlanStokes È possibile specializzare 'fun2' solo per restituire un tipo covariante (quindi deve essere derivato da' bar'), quindi è garantito che il tipo covariante abbia la stessa funzionalità (cioè deve avere un 'modello void fun0 () funzione const'). Quindi restituirà sempre un tipo che è in realtà una 'barra' –
texasflood