Domanda

Ho un comportamento strano con l'overload di un operatore in C++.Ho una classe e devo verificare se il suo contenuto è maggiore o uguale a un long double.Ho sovraccaricato l'operatore >= per effettuare questo controllo, la mia dichiarazione è la seguente:

bool MyClass::operator>=(long double value) const;

Devo dire che ho anche un operatore cast-to-long-double per la mia classe, che funziona senza eccezioni solo a determinate condizioni.Ora, quando utilizzo questo operatore, il compilatore si lamenta dell'uso ambiguo di operator>= e le alternative sono:

  • Mio.
  • L'integrato operator>=(long double, int).

Ora, come faccio a forzare il programma a utilizzare il mio operatore?

È stato utile?

Soluzione

Aggiornamento 2015: o, se si vuole mantenere la capacità di conversione utilizzando la sintassi (double)obj invece la sintassi obj.to_double(), rendere la funzione di conversione explicit mettendo il prefisso con quella parola chiave. Avete bisogno di un cast esplicito poi per la conversione per innescare. Personalmente, preferisco la sintassi .to_double, a meno che la conversione sarebbe di bool perché in tal caso la conversione è utilizzato da if(obj) anche se è explicit, e che è molto più leggibile rispetto if(obj.to_bool()) a mio parere.


Eliminare l'operatore di conversione. Sarà causare problemi fino in fondo. Hanno una funzione come

to_double()

o simile che restituisce il valore doppio e chiamare quella funzione in modo esplicito per ottenere un doppio.

Per il problema a portata di mano, non c'è questo problema:

obj >= 10

Si consideri che l'espressione. L'operatore integrato corrisponde al primo argomento da una sequenza di conversione definita dall'utente per il tipo utilizzando l'operatore di conversione long double (). Ma la funzione corrisponde il secondo argomento da una sequenza conversione standard da int a long double (solidale alla conversione in virgola mobile). È sempre ambiguo quando ci sono conversioni per due argomenti, ma non almeno un argomento che può essere convertito migliore mentre i restanti argomenti non vengono convertiti peggiore per una chiamata. Nel tuo caso, quello incorporato corrisponde al secondo argomento migliore, ma il primo peggio, ma la funzione corrisponde al primo argomento migliore, ma la seconda peggiore.

E 'confuso, ecco alcuni esempi (le conversioni da char a int sono chiamati promozioni, che sono meglio di conversioni da char a qualcosa di diverso da int, che si chiama una conversione):

void f(int, int);
void f(long, long);
f('a', 'a');

Chiamate la prima versione. Perché tutti gli argomenti per la prima possono essere convertiti meglio. Allo stesso modo, il seguente sarà ancora chiamare la prima:

void f(int, long);
void f(long, long);
f('a', 'a');

Perché il primo può essere convertito meglio, e il secondo non viene convertito peggio. Ma ciò che segue è ambigua :

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

E 'più interessante in questo caso. La prima versione accetta il primo argomento da una corrispondenza esatta. La seconda versione accetta il secondo argomento da una corrispondenza esatta. Ma entrambe le versioni non accettano il loro altro argomento almeno altrettanto bene. La prima versione richiede una conversione per il suo secondo argomento, mentre la seconda versione richiede una promozione per il suo argomento. Così, anche se una promozione è meglio di una conversione, la chiamata alla seconda versione non riesce.

E 'molto simile al vostro caso di cui sopra. Anche se una sequenza standard di conversione (conversione da int / float / double a long double) è migliore che una sequenza di conversione definita dall'utente (conversione da MyClass a lungo doppio), la versione operatore non venga effettuata, perché il vostro altro parametro (long double) richiede una conversione da l'argomento che è peggio di quello che l'operatore integrato ha bisogno di tale argomento (perfetta corrispondenza).

risoluzione di sovraccarico è una questione complessa in C ++, così si può impossibilmente ricordare tutte le regole sottili in esso. Ma ottenere il piano di massima è del tutto possibile. Spero che ti aiuta.

Altri suggerimenti

Fornendo una conversione implicita in a double stai effettivamente affermando, la mia classe è equivalente a a double e per questo motivo non dovresti preoccuparti se l'operatore integrato >= for doubleviene utilizzato s.Se tu Fare attenzione, allora la tua classe non è davvero "equivalente" a a double e dovresti considerare di non fornire un file implicito conversione a double, ma fornendo invece un file esplicito Funzione membro GetAsDouble o ConvertToDouble.

Il motivo per cui al momento hai un'ambiguità è quello relativo a un'espressione t >= d Dove t è un'istanza della tua classe e d è double, il compilatore deve sempre fornire una conversione del lato sinistro o del lato destro, quindi l'espressione è davvero ambigua.O t'S operator double viene chiamato e l'operatore integrato >= for doubleviene utilizzato s oppure d deve essere promosso a a long double e viene utilizzato il tuo operatore membro >=.

Modifica, hai aggiornato la tua domanda per suggerire che la tua conversione è troppo lunga e il tuo confronto è contro un int.In tal caso l'ultimo paragrafo dovrebbe essere letto:

Il motivo per cui al momento hai un'ambiguità è quello relativo a un'espressione t >= d Dove t è un'istanza della tua classe e d è un int, il compilatore deve sempre fornire una conversione del lato sinistro o del lato destro, quindi l'espressione è davvero ambigua.O t'S operator long double viene chiamato e l'operatore integrato >= for long double E int viene utilizzato oppure d deve essere promosso ad a long double e viene utilizzato il tuo operatore membro >=.

Presumo si sta confrontando contro un int letterali, e non un long double:

MyClass o;

if (o >= 42)
{
   // ...
}

Se questo è il caso entrambe le alternative sono buoni / complesso.

Utilizzare il operator long double():

  1. MyClass::operator long double()
  2. built-in operator>=(long double, int)

Utilizzare il MyClass::operator>=(long double):

  1. built-in int conversione a long double
  2. MyClass::operator>=(long double)

Hai long double nella dichiarazione. Provare a cambiare a double.

L'utilizzo del overloading degli operatori combinata con fusione personalizzato può essere molto confusa per gli utenti della vostra classe. Chiedete a voi stessi, sarebbero gli utenti di questa classe aspettarsi a convertirsi in un doppio, o è comparabile con un letto? Non sarebbe avere una funzione .greaterThan (doppio) di raggiungere lo stesso obiettivo, ma senza sorprendere l'utente?

Credo che si potrebbe sempre lanciare in modo esplicito l'oggetto di raddoppiare prima di confrontare, per evitare l'ambiguità. Ma se fossi in te riconsiderare l'approccio di cui sopra e concentrarsi sulla scrittura del codice che è intuitivo e si comporta in un modo sorprendente, invece di fantasia tipo-casting e l'overloading degli operatori.

(Ispirato meraviglioso circa l'overloading degli operatori )

  • Il built-in operatore> = (long double, int).

Sembra che tu hai definito:

bool class::operator>=(long double value) { return value >= classValue; }

E vi manca:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

Quindi il compilatore non può decidere quale modo per convertire. (E 'ambiguo.)

Forse una funzione template (o metodo) sarebbe utile?

Attenzione per le situazioni in cui a> = b invoca metodi diversi rispetto b> = a .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top