Ho scoperto che quando si accede a un attributo non modello (v.foo
) da una variabile di un tipo di modello (T& v
), C++ può essere indotto a pensare che si tratti di un modello membro è una funzione modello con lo stesso nome (template class <T> void foo()
). Come può essere spiegato dalle specifiche C++? Considerate questo semplice programma:Nome attributo confuso C++ per il modello membro
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
Abbiamo una funzione template foo_negative
che prende un oggetto di qualsiasi tipo e determina se l'attributo foo è negativo. La funzione main
crea un'istanza di foo_negative
con [T = X]. Questo programma si compila e funziona senza output.
Ora, aggiungere questa funzione per la parte superiore del programma:
template <class T>
void foo()
{
}
compilazione con G ++ 4.6.3 risultati in questo errore di compilazione:
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(dove la linea 13 è return v.foo < 0
e La riga 25 è assert(!foo_negative(x))
.)
Clang produce errori simili.
Wat? In che modo l'aggiunta di una funzione non correlata mai chiamata riesce a introdurre un errore di sintassi in un programma valido? Durante l'analisi di foo_negative
, il compilatore non conosce il tipo di v
e, in modo cruciale, non sa se v.foo
è un modello membro o un membro normale. Apparentemente, deve decidere al momento dell'analisi (prima che il modello venga istanziato) se trattarlo come un modello membro o un membro normale.
Se pensa v.foo
è un membro template, quindi < 0
è visto come passare 0
come argomento di modello, e c'è manca un >
, quindi l'errore di sintassi. Quindi, quando foo_negative
viene istanziato con [T = X], c'è un altro errore perché X::foo
non è un modello membro.
Ma perché pensa che lo v.foo
sia un modello membro? Questa ambiguità è esattamente ciò che la parola chiave template
è per: se avessi scritto v.template foo
, avrei detto esplicitamente a C++ di aspettarmi un modello membro, ma non ho usato la parola chiave template
! Non ho fatto riferimento a un modello membro, quindi dovrebbe presumere che sia un membro normale. Il fatto che sia presente una funzione con lo stesso nome del membro non dovrebbe avere alcun effetto. Perché lo fa? Non può essere un bug nel compilatore perché GCC e clang sono coerenti.
Che strano. Compilare su gcc-4.3.4: http://ideone.com/FP3SO –
No, hai dimenticato di aggiungere la 'modello void foo()' dichiarazione: http://ideone.com/FxEBm Non si compila . –
mgiuca
forse è davvero un bug sia in gcc che in clang: [dichiarazione] (http://ideone.com/zofCF). Ho cambiato 'v.foo < 0' to '0 > v.foo' e compila bene. Forse entrambi i compilatori pensano che "<0" sia argomento di template, come hai detto nella domanda. – user2k5