5

Sto definendo più sovraccarichi dell'operatore assegnazione come segue:sovraccarichi booleani e stringhe dell'operatore di assegnazione (C++)

foo.h

class Foo 
{ 
private: 
    bool my_bool; 
    int my_int; 
    std::string my_string; 
public: 
    Foo& operator= (bool value); 
    Foo& operator= (int value); 
    Foo& operator= (const std::string& value); 
}; 

Foo.cpp

// Assignment Operators. 
Foo& Foo::operator= (bool value) {my_bool = value; return *this;} 
Foo& Foo::operator= (int value) {my_int = value; return *this;} 
Foo& Foo::operator= (const std::string& value) {my_string = value; return *this;} 

Ed ecco il mio main.cpp (vedere il commento contrassegnato SURPRISE):

Foo boolFoo; 
Foo intFoo; 
Foo stringFoo; 

// Reassign values via appropriate assignment operator. 
boolFoo = true;    // works...assigned as bool 
intFoo = 42;     // works...assigned as int 
stringFoo = "i_am_a_string"; // SURPRISE...assigned as bool, not string 

std::string s = "i_am_a_string"; 
stringFoo = s;     // works...assigned as string 

// works...but awkward 
stringFoo = static_cast<std::string>("i_am_a_string"); 

Domanda: Qualcuno può dirmi perché un valore letterale stringa non trasmesso viene valutato in un contesto booleano?

+0

@Mooing Anatra: Perché togliere le costruttori? Li ho aggiunti per indicare intenzionalmente che una variabile può essere *** inizializzata *** tramite un costruttore e quindi *** *** riassegnata tramite un operatore di assegnazione. (Come ho visto in altri post SO, a volte è necessario *** *** entrambi.) – DavidRR

+2

ho tagliato il codice a causa di [domande buone hanno un breve autonomo esempio compilabile] (http://sscce.org/) e [il tuo codice potrebbe essere significativamente più breve e più semplice e riprodurre ancora il problema] (http://ideone.com/W2nemc). Non ho letto la maggior parte della tua domanda la prima volta, perché aveva troppa parte del codice e ho indovinato (correttamente) che la maggior parte di essa non era correlata alla tua domanda. –

+0

@Mooing Duck: Sì, sono molto d'accordo in linea di principio e ho considerato questo quando aggiungo i costruttori al mio esempio. Ma rimanderò al tuo giudizio qui. Tuttavia, la mia speranza è che chiunque incontri il mio commento saprà prendere in considerazione anche i relativi contructor. – DavidRR

risposta

9

Il C++ standard definisce regole di risoluzione di sovraccarico nel capitolo 13.3, ci si trova:

13.3.3.2 Classifica sequenze conversione implicita [over.ics.rank]

Quando si confrontano le forme di base delle sequenze di conversione implicite (come definito in 13.3.3.1)

- una sequenza di conversione standard (13.3.3.1.1) è una sequenza di conversione migliore di una definita dall'utente sequenza di conversione o sequenza di conversione ellissi e

- una sequenza di conversione definita dall'utente (13.3.3.1.2) è una sequenza di conversione migliore rispetto a una sequenza di conversione ellissi (13.3.3.1.3).

Ciò significa che il compilatore preferisce una sequenza standard di conversione dalla stringa letterale bool o int se disponibile. Ora, quali conversioni standard sono rilevanti? Nel suo caso, questi due sono rilevanti:

4,2 Array a puntatore conversione [conv.array]

Un Ivalue o rvalue di tipo “vettore di NT” o “matrici del limite sconosciuto di T "può essere convertito in un valore di tipo" puntatore a T ". Il risultato è un puntatore al primo elemento dell'array.

Questa conversione trasforma la stringa letterale, che è di tipo const char[N], in un const char*. La seconda è:

4.12 conversioni booleane [conv.bool]

Un prvalue dell'aritmetica, censimento unscoped, puntatore o puntatore al Tipo di utente può essere convertito in un prvalue di digitare bool. Un valore zero, un valore puntatore nullo o un valore puntatore membro nullo viene convertito in false; qualsiasi altro valore viene convertito in true. Un valore di tipo std::nullptr_t può essere convertito in un valore di tipo bool; il valore risultante è false.

Questo è il motivo per cui il puntatore viene convertito in bool. Poiché esiste una sequenza di conversione standard, la conversione definita dall'utente in std::string non viene utilizzata.

Per risolvere il problema, suggerisco di aggiungere un'altra versione sovraccaricata che richiede const char* e inoltra la chiamata al sovraccarico const std::string&.

+0

Grazie, Daniel! L'altra lezione per me qui è che una stringa letterale è mappata a 'char *' (tramite 'char [N]'), * not * 'std :: string'. – DavidRR

+1

@DavidRR: quelli dovrebbero essere 'const char *' e 'const char [N]', ma sì. –

+0

+1 per aver citato lo standard e averlo spiegato. –

3

Daniel è giusto.

La risposta breve è che std::string non è un tipo built-in e, come tale, non ottiene alcun trattamento preferenziale magico. E, sfortunatamente, il tipo di stringa letterale come "hi world" è nonstd::string, ma un tipo di puntatore che si converte più facilmente nel tipo predefinito bool che nel "definito dall'utente" & dagger; tipo std::string.

In sostanza, la risposta è: Benvenuto C++.

& pugnale; Sì, lo so, è dalla libreria standard di e, no, non importa.

+0

Penso che qualcuno sia stato svalutato perché quell'ultima frase si presenta un po 'snella. –

+2

@Mooing: se è snarky, allora è snarky al C++. Se qualcuno lo sta prendendo personalmente, beh, sono al di fuori del mio aiuto. –

+0

Come poster della domanda, non sono affatto offeso dal "benvenuto in C++". Sto trovando C++ per essere abbastanza diverso da Java e C#. Con C++, sembra certamente che ci siano più opportunità di mettersi nei guai ... – DavidRR