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!
http://stackoverflow.com/questions/18596412/strange-error-with-a-templated-operator-overload Potrebbe aiutare? – IllusiveBrian
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
Stavo cercando di minimizzare ulteriormente il codice e rimosso 'A :: operator *' ... ma ho notato che questo impediva a GCC di compilare il codice. Interessante ... –