2014-10-16 8 views
8

Perché C++ esegue il casting della stringa letterale passo come bool anziché come stringa?Overloaded Bool/String Ambiguity

#include <iostream> 

using namespace std; 

class A 
{ 
    public: 
     A(string v) 
     { 
      cout << v; 
     } 

     A(bool v) 
     { 
      cout << v; 
     } 
}; 

int main() 
{ 
    A("hello"); 
    return 0; 
} 

uscita: 1

Forse perché il compilatore non è abbastanza intelligente per fare il salto da char * a corda e piuttosto appena presuppone che bool è la cosa più vicina a un puntatore? La mia unica opzione è quella di creare un costruttore di char esplicito che fondamentalmente fa esattamente la stessa cosa del costruttore di stringhe?

+1

Generalmente preferisco le conversioni esplicite. Le conversioni implicite hanno trucchi come questo. Vedi http://stackoverflow.com/q/2346083/10077 –

+0

Non sono sicuro ma: Entrambe le conversioni sono possibili (convertendo il puntatore in bool controlla il puntatore nullo). Ma la conversione in bool è una conversione * built-in *, mentre per string è una convinzione * definita dall'utente * (via implicito). E ora, se ricordo bene, i built-in hanno più priorità su quelli definiti dall'utente. – leemes

+1

possibile duplicato di [Sovraccarico metodo C++ non funzionante] (http://stackoverflow.com/questions/14770252/c-method-overload-not-working) –

risposta

12

Se si dispone di C++ 11 è possibile utilizzare un costruttore delegando:

A(char const* s) : A(std::string(s)) { } 

La ragione per la conversione booleano costruttore viene scelto su quello per std::string è perché la conversione char const*-bool è una conversione standard mentre quella a std::string è una conversione definita dall'utente. Le conversioni standard hanno un rango superiore rispetto alle conversioni definite dall'utente.

3

Con

A(string("hello")); 

che darà il risultato previsto.

Perché è così?

È causa delle conversioni standard:

  • "ciao" è inteso come un puntatore const char*
  • questo puntatore può essere convertito in un (sezione 4.12 della norma bool: "A prvalue di (...) il tipo di puntatore (...) può essere convertito in un valore di tipo bool. ")
  • la conversione da" ciao "a string non è considerata poiché la sezione 12.3 dello standard spiega che" Le conversioni di tipi di oggetti di classe possono essere specificate dai costruttori e dalle funzioni di conversione. Queste conversioni sono chiamati definita dall'utente conversioni "e" conversioni definite dall'utente vengono applicate solo dove sono inequivocabili". Non ti hanno il bool costruttore di conversione std::string sarebbe fatto implicitamente.

Come per ottenere ciò che vi aspettavate

Basta aggiungere il costruttore mancante per litterals stringa:?

A(const char* v) 
{ 
    cout << v; // or convert v to string if you want to store it in a string member 
} 

Ovviamente, invece di riscrivere un costruttore da zero, è possibile optare per un delegato come suggerito da 0x499602D2 in un'altra risposta.

+0

Sì, ma non voglio digitare 'stringa (. ..) 'ogni volta. È la mia unica altra opzione per creare un costruttore che accetta un 'char const *' come argomento? – RPGillespie

+0

Sì! ho completato con spiegazioni aggiuntive. – Christophe

2

nella scelta di un metodo di overload questo è l'ordine che il compilatore cerca:

  1. corrispondenza esatta
  2. Promozione
  3. standard numerico di conversione
  4. operatori definiti dall'utente

Un puntatore non promuove a bool ma converte in bool. Un char* utilizza un operatore std per convertire in std::string. Notare che se char* utilizza lo stesso numero in questo elenco per convertire in siabool e std::string sarebbe ambiguo quale metodo sceglierebbe il compilatore, quindi il compilatore genererebbe un errore di "sovraccarico ambiguo".

Vorrei buttare il mio peso dietro la soluzione 0x499602D2. Se hai C++ 11 la cosa migliore da fare è chiamare: A(char* s) : A(std::string(s)){} Se non hai C++ 11 allora creo un costruttore A(char* s) e astratto la logica del costruttore A(std::string) in un metodo e chiamo quel metodo da entrambi costruttori.

http://www.learncpp.com/cpp-tutorial/76-function-overloading/

2

Recentemente ho superato anche questo problema, mi permetta di condividere un altro modo.

È possibile modificare il costruttore bool in un unsigned char. Quindi il decadimento e la conversione implicita di string letterale non avvengono e viene eseguito il costruttore std::string.

class A 
{ 
public: 
    A(string v) 
    { 
     cout << v; 
    } 

    A(unsigned char v) 
    { 
     cout << static_cast<bool>(v); 
    } 
}; 

int main() 
{ 
    A("Hello"); // <- Call A(string) 
    A(false); // <- Call A(unsigned char) 
} 

In questo modo non è necessario fornire sempre Sovraccarichi di std::string e const char* né rendere il codice gonfiare la costruzione del std::string al luogo di chiamata del cliente.

Non sostengo che sia meglio, ma è più semplice.

+0

Ho avuto lo stesso problema, ma mi chiedo perché A ("Ciao"); non dà un avvertimento, ma const char * b = "Hello"; A (b); dà l'avviso 4800: forzare il valore in bool 'true' o 'false'? –

+0

Questo ha funzionato anche per me ed è anche estremamente utile con il nuovo 'string_view's. Vedi [qui] (https://godbolt.org/g/1uCwR2) per un esempio. – Claudius