2014-10-16 15 views
8

Warum wirft C++ das String-Literal, das ich als Bool anstelle von String übergebe?Overloaded Bool/String Mehrdeutigkeit

#include <iostream> 

using namespace std; 

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

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

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

Ausgang: 1

Ist es, weil der Compiler nicht intelligent genug, um den Sprung von char * string zu machen und eher davon ausgegangen, dass nur Bool die nächste Sache zu einem Zeiger ist? Ist meine einzige Option, einen expliziten char * -Konstruktor zu erstellen, der genau dasselbe wie der Zeichenkettenkonstruktor tut?

+1

Ich bevorzuge in der Regel explizite Konvertierungen. Implizite Conversions haben so etwas. Siehe http://stackoverflow.com/q/2346083/10077 –

+0

Ich bin mir nicht sicher, aber: Beide Konvertierungen sind möglich (Konvertieren von Zeiger auf bool überprüft Nullzeiger). Das Konvertieren in bool ist jedoch eine * eingebaute * Konvertierung, während zu string eine * benutzerdefinierte * convsion (über implizite c'tor) ist. Und jetzt, wenn ich mich richtig erinnere, haben Built-Ins mehr Priorität als benutzerdefinierte. – leemes

+1

möglich Duplikat von [C++ Methode Überladung funktioniert nicht] (http://StackOverflow.com/Questions/14770252/c-method-overload-not-working) –

Antwort

12

Wenn Sie C++ 11 Sie delegieren Konstruktor verwenden:

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

Der Grund für die boolean Umwandlung-Konstruktor über dem für std::string gewählt ist, weil die Umwandlung char const*-bool ist eine Standardkonvertierung, während die eine std::string eine benutzerdefinierte Konvertierung ist. Standardkonvertierungen haben einen höheren Rang als benutzerdefinierte Conversions.

3

Mit

A(string("hello")); 

wird es das erwartete Ergebnis.

Warum ist es so?

Es ist, weil die Standard-Conversions:

  • "Hallo" als const char* Zeiger verstanden wird
  • diese Zeiger auf einen bool (Abschnitt 4.12 der Norm umgewandelt werden: „A prvalue von (...) pointer (...) type kann in einen prvalue des Typs bool konvertiert werden. ")
  • Die Konvertierung von" hallo "zu string wird nicht berücksichtigt, da Abschnitt 12.3 des Standards erklärt, dass" Typkonvertierungen von Klassenobjekten können durch Konstruktoren und durch Konvertierungsfunktionen festgelegt werden. Diese Umwandlungen werden benutzerdefinierte genannt Konvertierungen „und“ Benutzerdefinierte Konvertierungen werden nur dort eingesetzt, wo sie eindeutig sind“. Würden Sie nicht haben den bool Konstruktor die std::string Konvertierung implizit erfolgen würde.

Wie zu bekommen, was Sie

einfach erwartet, dass die fehlende Konstruktor für String litterals hinzufügen:

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

Anstatt einen Konstruktor von Grund auf neu zu schreiben, können Sie natürlich auch einen Delegaten wählen, wie in einer anderen Antwort von 0x499602D2 vorgeschlagen.

+0

Ja, aber ich möchte nicht string (. ..) 'jedes Mal. Ist meine einzige andere Option, einen Konstruktor zu erstellen, der ein 'char const *' als Argument verwendet? – RPGillespie

+0

Ja! Ich habe mit zusätzlichen Erklärungen abgeschlossen. – Christophe

2

Wenn eine überladene Methode der Auswahl dies ist die Reihenfolge, dass der Compiler versucht:

  1. Exact Match
  2. Promotion
  3. Standard-numerische Umwandlung
  4. Benutzer definierten Operatoren

Ein Zeiger nicht zu bool fördern, aber es konvertiert zu bool. A char* verwendet einen Operator std, um zu std::string zu konvertieren. Beachten Sie, dass wenn char* die gleiche Nummer in dieser Liste verwendet, um in beidebool und std::string zu konvertieren wäre es mehrdeutig, welche Methode der Compiler wählen sollte, so würde der Compiler einen "mehrdeutigen Überlastungs" -Fehler werfen.

Ich würde mein Gewicht hinter 0x499602D2 's Lösung werfen. Wenn Sie C++ 11 haben, rufen Sie am besten an: A(char* s) : A(std::string(s)){} Wenn Sie C++ 11 nicht haben, dann würde ich einen A(char* s) Konstruktor erstellen und die Logik des A(std::string) Konstruktors in eine Methode abstrahieren und diese Methode von beiden aufrufen Konstruktoren.

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

2

Kürzlich kam ich auch dieses Problem, lassen Sie mich eine andere Art und Weise teilen. Sie können den bool Konstruktor in einen unsigned char ändern. Also die Verfall und implizite Umwandlung von String-Literal nicht passieren, und der std::string Konstruktor findet statt.

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) 
} 

Auf diese Weise brauchen Sie nicht immer überlastet zu std::string und const char* bieten weder Code aufblasen machen die std::string auf der Client-Aufrufstelle aufzubauen.

Ich behaupte nicht, dass es besser ist, aber es ist einfacher.

+0

Ich hatte das gleiche Problem, aber ich frage mich, warum A ("Hallo"); gibt keine Warnung, aber const char * b = "Hallo"; A (b); gibt Warnung 4800: Erzwingt einen Wert, um 'wahr' oder 'falsch' zu boolen? –

+0

Das funktionierte auch für mich und ist auch sehr nützlich mit den neuen 'string_view's. Ein Beispiel finden Sie [hier] (https://godbolt.org/g/1uCwR2). – Claudius

Verwandte Themen