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

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

以上代碼編譯成功由於類型轉換,即使字符數組被傳遞其中bool預期。如何防止隱式轉換從char數組爲bool

是否有可能導致此代碼編譯失敗? (C++ 03解決方案是首選,因爲我工作場合的編譯器很古老。)

我已經看過以下有關StackOverflow的相關問題,但他們沒有完全解決這個問題。 Preventing implicit conversion in C++Why does the compiler choose bool over string for implicit typecast of L""?

+5

你是** **不傳遞一個'的std :: string'。你正在傳遞一個'const char [5]'。這會衰變爲一個'const char *',它被轉換爲'bool'。 – juanchopanza

+0

@juanchopanza是的,抱歉,我發現後發佈。我現在已經更新了這個問題。 –

回答

9

你可以聲明一個函數,const char*並沒有提供一個定義:

void setBar(const char*); 

這將使它無法在鏈接時。你還是會離開所有其他隱式轉換,雖然 - 從任何指針BOOL,積分爲bool,漂浮到bool ...

另一種選擇:

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

這樣你會得到一個如果您使用bool以外的其他名稱進行調用,則表示它是私人的錯誤。

+1

'私人'呢?我們可以使用它嗎? –

+0

@Afriza,當然,它會以不同的錯誤信息失敗。 – jrok

+1

鏈接時失敗不如編譯時失敗。因此private:void setBar(const void *);沒有定義。另外我建議不要使用模板(假設你有一個bool包裝類)。 –

7

一種選擇將是使setBar模板,並允許它僅與bool工作:

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

或者,你可以使用SFINAE與std::enable_if達到同樣的效果,雖然編譯器警告可能不太容易閱讀:

struct Foo 
{ 
    template<class T , 
      class = typename std::enable_if<std::is_same<bool,T>::value>::type > 
    void setBar(T bar_) 
    { 
     bar = bar_; 
    } 
    bool bar; 
}; 
+1

這,你可以使用BOOST_STATIC_ASSERT爲C++ 03解決方案。 – jrok

+0

我也會提到'std :: enable_if'。 – lapk

+1

@PetrBudnik好主意,我添加了一個例子。 – juanchopanza

5

有一個共同的習語,既避免了這個問題,並提供其他優點。您可以創建一個自定義類型,而不是使用bool,以更清楚地描述它所代表的狀態。

bool類型僅表示truefalse的通用值,而在實際使用中,您將這些狀態重載爲意味着更具體。下面是使用的枚舉定義新類型的例子:

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 
} 

這仍然允許從任何算術或浮動型隱式轉換。爲了避免這種情況,你可以使用C++ 11的enum class,或推出自己的強類型的布爾是這樣的:

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

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