Impliziter Cast von char* nach bool



  • Guten Tag liebe Gemeinde.

    Hier mal ein Problem, was ich mir absolut nicht herleiten kann. Es wird ein char-Array(char*) implizit nach bool gecastet. Ich könnte mir vorstellen, dass die Adresse als long int gesehen wird. Und damit dann zu int und dann schliesslich zu bool. Aber seht selbst:

    #include <iostream>
    
    struct MyClass {
    	MyClass( bool x ) {
    		std::cout << "Bool-Konstruktor mit x=" << x << std::endl;
    	}
    };
    
    int main( ) {
    	MyClass mc( "input" );
    	return 0;
    }
    

    Konsole:

    > g++ -Wall -pedantic boolString.cpp -o boolString
    > ./boolString
    Bool-Konstruktor mit x=1
    >
    

    Die Frage ist hier, wieso der Kompiler das macht, und wie man das verhindert?
    Ich richtigen Programm(woraus das Problem ist), habe ich den Operator << einer Klasse X überladen. Beispielsweise für die Klassen Date und String:

    #include <iostream>
    
    struct String {
    	String( const char *str = 0 ) { }
    	String( const String& str ) { }
    };
    
    struct Date {
    	Date( const bool readCurrent = false ) { }
    };
    
    struct X {
    	X& operator<<( const String &str ) {
    		std::cout << "operator<<( string )" << std::endl;
    		return *this;
    	}
    	X& operator<<( const Date &dat ) {
    		std::cout << "operator<<( date )" << std::endl;
    		return *this;
    	}
    	X& operator<<( const int &i ) {
    		std::cout << "operator<<( date )" << std::endl;
    		return *this;
    	}
    };
    
    int main( ) {
    	X x;
    	Date dat( true );
    	x << 42;
    	x << "foo"; // ambiguous overload
    	x << dat;
    
    	return 0;
    }
    

    Konsole:

    > g++ -Wall -pedantic boolString.cpp -o boolString
    boolString.cpp: In function ‘int main()’:
    boolString.cpp:32:7: error: ambiguous overload for ‘operator<<’ in ‘x << "foo"’
    boolString.cpp:32:7: note: candidates are:
    boolString.cpp:13:5: note: X& X::operator<<(const String&)
    boolString.cpp:17:5: note: X& X::operator<<(const Date&)
    >
    

    Wie kann man das Problem beheben im genannten Beispiel?

    MfG. Christoph



  • Du könntest den Konstruktor von Date explicit machen. Dann gibt es keine implizite Umwandlung von bool nach Date mehr, man muss dann immer bspw. Date(true) schreiben (was IMHO auch unabhängig von dem Überladungsproblem sinnvoll ist in diesem Fall.)



  • Pointer sind implizit nach bool konvertierbar, das ist eine eingebaute Konvertierung.

    Der Compiler sieht bei den beiden op<<-Kandidaten für Date die Konvertierung char* -> bool -> Date und für String die Konvertierung char* -> String

    Dass bei der Konvertierung in ein Date noch eine eingebaute Konvertierung nötig ist, macht nichts, dem Compiler ist beides eine User defined conversion.

    Abgesehen davon, den Ctor explicit zu machen, könntest du noch überlegen, eine Proxy-Klasse für bool zu schreiben und statt des bool dann die als Parameter zu nehmen:

    struct StrongBool
    {
      StrongBool(bool b) : value(b) {}
      bool value;
    };
    
    class Date {
    public:
      Date(StrongBool readCurrent = false ) { }
    };
    


  • Noch besser wäre natürlich den bool Parameter weg zu werfen. Date(false) sagt nicht viel aus. Viel cooler wäre hier zB ein kompletter wegfall eines etwaigen parameters oder wenn er doch notwendig ist einen enum nehmen.

    Ich weiß leider nicht was der Parameter macht deshalb kann ich keine besseren Vorschläge bringen...



  • enum 👍
    bool ist da irgendwie nicht so toll.



  • Hört sich gut an. Ich werds so machen, dass die Date-Klasse statt des bool-Parameters ein enum bekommt. Das ist dann auch aussagekräftiger und die Konvertierung verschwindet automatisch.

    Danke für die Hilfe! 🙂


Anmelden zum Antworten