2014-10-25 9 views
15

Il seguente codice minimo compila il g ++, ma non verrà compilato il clang ++:Questo codice è valido? Funziona con gcc, non funzionano con clangore

template<class T> 
T operator*(float a, const T& b) 
{ 
    return b * a; 
} 

struct A{ 
    A operator*(float b) const 
    { 
     A a; 
     return a; 
    } 
}; 

int main() 
{ 
    A a; 
    2.0f * a; 
} 

Questo è l'errore che ottengo:

$ clang++ test.cpp 
test.cpp:2:3: error: overloaded 'operator*' must have at least one parameter of 
     class or enumeration type 
T operator*(float a, const T& b) 
^
test.cpp:4:11: note: in instantiation of function template specialization 
     'operator*<float>' requested here 
     return b * a; 
       ^
test.cpp:18:10: note: in instantiation of function template specialization 
     'operator*<A>' requested here 
    2.0f * a; 
     ^
1 error generated. 

Clang versione 3.5. Questo codice è valido? C'è un bug su Clang?

+5

http://stackoverflow.com/questions/18596412/strange-error-with-a-templated-operator-overload Potrebbe aiutare? – IllusiveBrian

+2

Penso che @Namfuak abbia trovato un duplicato: l'espressione 'b * a' tenta di creare un'istanza del modello di funzione dell'operatore, che porta a dedurre' T' come 'float', e la specializzazione prodotta (una funzione dell'operatore) è illecita- formato, poiché non ha parametri di tipo classe/enumerazione o riferimento. Questo sembra non essere un fallimento di sostituzione, cioè un errore difficile. Vedi [over.oper]/1 e/6. – dyp

+0

Stavo cercando di minimizzare ulteriormente il codice e rimosso 'A :: operator *' ... ma ho notato che questo impediva a GCC di compilare il codice. Interessante ... –

risposta

2

2.0f * a; istanze ::operator*<A>. All'interno di tale funzione, abbiamo l'espressione b * a, che, se si guardano i tipi (semplificati), è A * float. A questo punto, il compilatore deve fare una scelta. Dovrebbe essere * la funzione globale ::operator*<float> (perché l'argomento della mano destra è float) o dovrebbe essere A::operator*? Per noi umani, è chiaro che dovrebbe essere A::operator*, ma dal punto di vista del compilatore non è immediatamente chiaro.

Quindi cosa fa il compilatore? Per prima cosa cerca di trovare tutte le funzioni operator* che potrebbe utilizzare (dopo di che cerca di determinare esattamente quale utilizzare). Una delle funzioni operator* che potrebbe utilizzare è ::operator*<float>. Ma aspetta, che cos'è ::operator*<float>? È float *(float, const float&)! E non possiamo farlo! Non è possibile sovraccaricare gli operatori per i tipi primitivi (immagina il caos se sovraccarichi int +(int, int) così fai fare a 1 + 2 qualcosa di completamente diverso da quello che tutti si aspettavano che facesse).

A questo punto, il programma è mal formato. Il semplice fatto che il compilatore tenterà anche di istanziare ::operator*<float> invalida il programma nel suo complesso. Quindi cosa possiamo fare? Dire al compilatore esattamente cosa fare:

template<class T> 
T operator*(float a, const T& b) 
{ 
    // This prevents the compiler from instantiating ::operator*<float> 
    return b.operator*(a); 

    // The above is meant to illustrate how the fix needs to work: it needs 
    // to avoid instantiating ::operator*<float>. Other methods can be used 
    // (like SFINAE) that might be more elegant (check out Walter's answer 
    // in the duplicate: https://stackoverflow.com/a/18596809/1287251), but 
    // in the end any solution used must avoid ::operator*<float>. 
} 

struct A{ 
    A operator*(float b) const 
    { 
     A a; 
     return a; 
    } 
}; 

int main() 
{ 
    A a; 
    2.0f * a; 
} 

Insomma, per rispondere alla domanda: no, il codice non è valido. È necessario impedire al compilatore di provare a creare un'istanza ::operator*<float>.

This is explained by @dyp in the comments e by @TemplateRex in the duplicate question. Tuttavia, ho dovuto leggere le loro risposte diverse volte prima di capire cosa volessero dire. Ho provato a semplificare le cose in questa risposta. Se posso migliorarlo, per favore fatemelo sapere!

Problemi correlati