2012-04-23 20 views
10

MODIFICA: seguendo il commento di Mike Seymour, ho sostituito operator std::string() const; con operator char *() const; e modificato di conseguenza l'implementazione. Ciò consente il cast implicito, ma, per qualche ragione, l'operatore long int unsigned ha la precedenza sull'operatore char *, che non sembra giusto ... Inoltre, non voglio esporre roba C cattiva come char * al di fuori del classe, quando ho std :: string. Ho la sensazione che la mia classe CustomizedInt debba ereditare da alcune cose per supportare la funzione che desidero. Qualcuno potrebbe elaborare il commento di Mike riguardo a std::basic_string? Non sono sicuro di averlo capito bene.Operatori di conversione implicita C++ Precedenza


ho questo pezzo di codice:

#include <string> 
#include <sstream> 
#include <iostream> 

class CustomizedInt 
{ 
private: 
    int data; 
public: 
    CustomizedInt() : data(123) 
    { 
    } 
    operator unsigned long int() const; 
    operator std::string() const; 
}; 

CustomizedInt::operator unsigned long int() const 
{ 
    std::cout << "Called operator unsigned long int; "; 
    unsigned long int output; 
    output = (unsigned long int)data; 
    return output; 
} 

CustomizedInt::operator std::string() const 
{ 
    std::cout << "Called operator std::string; "; 
    std::stringstream ss; 
    ss << this->data; 
    return ss.str(); 
} 

int main() 
{ 
    CustomizedInt x; 
    std::cout << x << std::endl; 
    return 0; 
} 

che stampa "operatore Chiamato unsigned long int; 123". Le mie domande sono queste:

  1. Dopo aver rimosso l'operatore unsigned long int, perché devo eseguire il cast x su std :: string in modo esplicito? Perché non chiama direttamente l'operatore di cast implicito (std :: string)?
  2. C'è qualche documentazione che spiega quali sono i cast impliciti ammessi e quale è il loro ordine di precedenza? Sembra che se aggiungo un operatore unsigned int a questa classe insieme all'operatore unsigned long int, ricevo un errore del compilatore relativo all'ambiguità per l'operatore < < ...
  3. Inoltre, so che la definizione di un simile operatore può essere cattiva pratica, ma non sono sicuro di comprendere appieno i caveat associati. Qualcuno potrebbe descriverli per favore? Sarebbe una pratica migliore definire solo i metodi pubblici ToUnsignedLongInt e ToString?
+0

Questo è relativo: [Errore di risoluzione di sovraccarico durante lo streaming dell'oggetto tramite conversione implicita in stringa] (http://stackoverflow.com/questions/6677072/overload-resolution-failure-when-streaming-object-via-implicit-conversion -to-str) –

+0

@Als: Facciamolo piano ... Non sono ancora pronto ad immergermi nei template :) –

risposta

8

Dopo tolgo l'operatore unsigned long int, perché ho bisogno di gettare x a std :: string in modo esplicito? Perché non chiama direttamente l'operatore di cast implicito (std :: string)?

La versione di << per archi è un modello, parametrizzato per i parametri del modello std::basic_string (std::string stessa essendo una specializzazione di tale modello). Può essere scelto solo dalla ricerca dipendente dall'argomento e funziona solo se l'argomento è in realtà una specializzazione di std::basic_string, non qualcosa di convertibile in questo.

C'è qualche documentazione che spiega quali sono i cast impliciti ammessi e quale è il loro ordine di precedenza?

Le regole sono piuttosto complesse e per la storia completa è necessario leggere lo standard C++. Semplici regole empiriche sono che le conversioni implicite non possono contenere più di una conversione definita dall'utente e (come hai scoperto) il risultato di una conversione implicita non può essere utilizzato per scegliere una specializzazione del modello mediante la ricerca dipendente dall'argomento.

Non sono sicuro di comprendere appieno le avvertenze associate. Qualcuno potrebbe descriverli per favore?

Non li capisco completamente; le interazioni tra conversioni implicite, ricerca del nome e specializzazione del modello (e probabilmente altri fattori che non riesco a pensare in questo momento) sono piuttosto complesse e la maggior parte delle persone non ha la tendenza a impararle tutte.Ci sono alcuni casi in cui la conversione implicita non avverrà, e altri in cui potrebbe accadere quando non te l'aspetti; personalmente, trovo più semplice evitare le conversioni implicite il più delle volte.

Sarebbe meglio fare una semplice definizione dei metodi pubblici ToUnsignedLongInt e ToString?

Questa è probabilmente una buona idea, per evitare conversioni indesiderate. È possibile risolvere il problema da loro lasciando e utilizzarli in modo esplicito quando necessario:

std::cout << std::string(x) << std::endl; 

In C++ 11, è possibile dichiarare loro explicit, in modo che possano essere utilizzati solo in questo modo. Secondo me, questa sarebbe l'opzione migliore se possibile; altrimenti, userei le funzioni di conversione esplicite come suggerisci.

A proposito, il tipo di reso di main() deve essere int, non void.

+0

Mike: Grazie per il tempo dedicato a fornire un commento così dettagliato. Fa chiarire un po 'le cose. Inoltre, grazie per aver individuato quel piccolo problema con "void main". Dovrei ricordarmi di usare la versione corretta, non importa cosa :) –