2015-07-29 16 views
9

Voglio usare una semplice struct con variabili membro denominate start e end in un modello di funzione:"fine" non è possibile utilizzare in funzione template

#include <iostream> 
using namespace std; 

struct st { 
    int start; 
    int end; 
}; 

template<typename T> 
void compare(const T& v1, const T& v2){ 
    if(v1.end < v2.end) 
     cout << "v1 < v2" << endl; 
} 

int main() { 
    st a = {1, 2}; 
    st b = {2, 3}; 
    compare(a, b); 
    return 0; 
} 

Ma questo programma non riesce a compilare su mingw g ++ 4.8.2 con :

main.cpp: In function 'void compare(const T&, const T&)': 
main.cpp:11:11: error: parse error in template argument list 
    if(v1.end < v2.end) 
     ^
main.cpp: In instantiation of 'void compare(const T&, const T&) [with T = st]': 
main.cpp:18:17: required from here 
main.cpp:11:5: error: 'end' is not a member template function 
    if(v1.end < v2.end) 
    ^

Perché no? Cosa c'è che non va nel mio codice?

+0

qual è l'esatto messaggio di errore? A proposito, il tipo di test non è definito da nessuna parte. – billz

+0

1.La riga "Test test" deve essere eliminata e dimenticata. Voglio un mini-codice da leggere. 2. il messaggio di errore è: test.cpp: nella funzione membro 'void compare (const T &, const T &)': test.cpp: 14: 15: errore: errore di analisi nell'elenco degli argomenti del modello if (v1.end < v2.end) – xiao

+0

Quale compilatore? – 0x499602D2

risposta

9

Questo è chiaramente un bug di gcc (in particolare 10200 sebbene ci siano molti duplicati con molti esempi diversi). [Temp.names] afferma:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template . Otherwise the name is assumed to name a non-template.[ Example:

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 
} 

—end example ]

v1 e v2 sono dipendente dal tipo, quindi il nome dovrebbe essere assunta per citarne senza modello a causa della template parola omessa e il < dovrebbero essere trattati come meno di, esattamente come nell'esempio sopra.

Senza contare che [basic.lookup.classref] afferma che:

The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.

E end dovrebbe chiaramente essere trovato nella classe dell'espressione oggetto - è una variabile membro semplice, dopo tutto.Il fatto che si tratti di un errore per end solo a causa della collisione con std::end() supporta ulteriormente l'idea di bug dal momento che quell'ambito non avrebbe mai dovuto essere considerato per cominciare.

Divertente, la soluzione più semplice è semplicemente: don't use using namespace std;!

0

Sembra che g ++ 4.8.4 abbia anche problemi quando la variabile membro è begin o end.

Utilizzando

struct st{ 
    int begin; 
    int end; 
}; 

template <typename T> 
void compare(const T& v1, const T& v2){ 
    if(v1.begin < v2.begin) 
    { 
     cout << "v1.begin < v2.begin" << endl; 
    } 
    if(v1.end < v2.end) 
    { 
     cout << "v1.end < v2.end" << endl; 
    } 
} 

produce il seguente messaggio di errore per me.

socc.cc: In function ‘void compare(const T&, const T&)’: 
socc.cc:12:11: error: parse error in template argument list 
    if(v1.begin < v2.begin) 
     ^
socc.cc:16:11: error: parse error in template argument list 
    if(v1.end < v2.end) 
     ^
socc.cc: In instantiation of ‘void compare(const T&, const T&) [with T = st]’: 
socc.cc:25:17: required from here 
socc.cc:12:5: error: ‘begin’ is not a member template function 
    if(v1.begin < v2.begin) 
    ^
socc.cc:16:5: error: ‘end’ is not a member template function 
    if(v1.end < v2.end) 

Forse qualcuno più familiarità con g ++ sviluppo di me in grado di fornire ulteriori dettagli.

Una soluzione è evitare l'uso di begin e end come variabili membro.

struct st{ 
    int _begin; 
    int _end; 
}; 

o

struct st{ 
    int _start; 
    int _end; 
}; 
+0

Hai ragione! Penso che sia un bug! può essere! – xiao

8

in realtà è la < che confondono il compilatore, dal momento che non sa se è l'inizio di un'espressione modello o il comparatore.

Dal @R Sahu chiesto un fonti ufficiali, ecco la spiegazione:

The paragraph that matters here is [basic.lookup.classref]p1:

"In a class member access expression (5.2.5), if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list (14.2) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template."

Since v is dependent, presumably the identifier is not found so we consider what happens if we look in the context of the entire postfix-expression. Since we find a function template, we should not conclude that we have the start of a template-id.

Fonte: C++ confusing attribute name for member template

Ed ecco il corrispondente gcc bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10200

* Paolo Carlini 2015-06-23 15:03:03 UTC *

Bug 65878 has been marked as a duplicate of this bug.

* Colin MacKenzie 2015-06-23 22:19:29 UTC *

Had this one today. Strange that it compiles fine in 4.4.6 but not in 4.8.2.

error: parse error in template argument list 
Ex: assert(block.begin < block.end); 

works when I parenthesize the block.begin 
Ex. assert((block.begin) < block.end); 

* Paolo Carlini 2015-06-23 22:21:28 UTC *

This should be fixed ASAP, but I'm not actively working on it at the moment.

0

Penso, per il momento, è possibile controllare le condizioni in ordine inverso.

#include <iostream> 
using namespace std; 

struct st { 
    int start; 
    int end; 
}; 

template<typename T> 
void compare(const T& v1, const T& v2){ 
    if(v2.end > v1.end) //changed the comparison order 
     cout << "v1 < v2" << endl; 
} 

int main() { 
    st a = {1, 2}; 
    st b = {2, 3}; 
    compare(a, b); 
    return 0; 
} 
Problemi correlati