2013-08-27 12 views
8
struct Foo { 
    void setBar(bool bar_) { bar = bar_; } 
    bool bar; 
}; 

int main() { 
    Foo f; 
    f.setBar("true"); 
} 

Der obige Code zu Typumwandlung erfolgreich kompiliert aufgrund Bool, obwohl ein char-Array übergeben wird, wo ein bool erwartet wird.Wie implizite Konvertierung von char-Array verhindern

Kann dieser Code nicht kompiliert werden? (C++ 03 Lösung bevorzugt, da der Compiler an meinem Arbeitsplatz alt ist.)

Ich habe die folgenden verwandten Fragen zu StackOverflow angeschaut, aber sie adressieren dieses Problem nicht ganz. Preventing implicit conversion in C++, Why does the compiler choose bool over string for implicit typecast of L""?

+5

Sie sind ** ** nicht vorbei eine 'std :: string'. Sie übergeben ein 'const char [5]'. Dies wird zu einem 'const char *', das in 'bool' umgewandelt wird. – juanchopanza

+0

@juanchopanza Ja, tut mir leid, das habe ich nach dem Posten bemerkt. Ich habe die Frage jetzt aktualisiert. –

Antwort

9

Sie können eine Funktion deklarieren, die const char* und bieten keine Definition nimmt:

void setBar(const char*); 

Dies wird es zu Verbindungszeitpunkt nicht machen. Du bist immer noch werden alle anderen implizite Konvertierung verlassen, obwohl - von jedem Zeiger auf bool, integraler Bestandteil Bool, Bool schwimmt auf ...

Eine weitere Option:

struct Foo { 
    void setBar(bool bar_) {} 
private: 
    template<typename T> 
    void setBar(T bar) {} 
}; 

diese Weise erhalten Sie eine bekommen Fehler, dass es privat ist, wenn Sie es mit etwas anderem als bool aufrufen.

+1

Was ist mit 'privat'? Können wir das benutzen? –

+0

@Afriza, sicher, es wird nur mit anderen Fehlermeldung fehlschlagen. – jrok

+1

Fehler bei der Verbindungszeit ist nicht so gut wie ein Fehler bei der Kompilierung. Daher private: void setBar (const void *); ohne Definition. Außerdem empfehle ich, keine Vorlage zu verwenden (stellen Sie sich vor, Sie haben eine Wrapperklasse um einen Bool). –

7

Eine Option wäre setBar eine Vorlage zu machen, und lassen Sie es nur mit bool arbeiten:

#include <type_traits> 

struct Foo 
{ 
    template <typename T> 
    void setBar(T bar_) 
    { 
    static_assert(std::is_same<bool,T>::value, "not bool"); 
    bar = bar_;   
    } 
    bool bar; 
}; 

int main() { 
    Foo f; 
    f.setBar(true); // OK 
    f.setBar("true"); // Error 
    f.setBar(1);  // Error 
} 

Alternativ können Sie SFINAE mit std::enable_if auf den gleichen Effekt verwenden, obwohl die Compiler-Warnung weniger sein könnte leicht zu lesen:

+1

Dies und Sie können BOOST_STATIC_ASSERT für C++ 03 Lösung verwenden. – jrok

+0

Ich würde auch 'std :: enable_if' erwähnen. – lapk

+1

@PetrBudnik Gute Idee, ich habe ein Beispiel hinzugefügt. – juanchopanza

5

Es gibt eine allgemeine Redewendung, die dieses Problem vermeidet und andere Vorteile bietet. Anstatt bool zu verwenden, können Sie einen benutzerdefinierten Typ erstellen, der den von ihm repräsentierten Status deutlicher beschreibt.

Der Typ bool stellt nur einen allgemeinen Wert von true oder false, während in der tatsächlichen Nutzung Sie diese Zustände sind Überlastung etwas präziser bedeuten. Hier ist ein Beispiel eines ENUM unter Verwendung eines neuen Typs zu definieren:

enum Bar { ok, foobar }; 

struct Foo { 
    void setBar(Bar bar_) { bar = bar_; } 
    Bar bar; 
}; 

int main() { 
    Foo f; 
    f.setBar(foobar); // ok 
    f.setBar("true"); // error 
} 

Diese noch implizite Konvertierung von jeder arithmetischen oder schwimmenden Typ ermöglicht. Um dies zu vermeiden, können Sie C++ 11 des enum class verwenden, oder rollen Sie Ihre eigenen stark typisierte Bool wie folgt aus:

template<class Tag> 
struct Bool { bool value; }; 

typedef Bool<struct BarTag> Bar; 
const Bar Ok = { false }; 
const Bar FooBar = { true }; 
Verwandte Themen