在我自己的代碼中出現錯誤後,編譯器選擇了錯誤的超載,我一直在挖掘一個解釋,但找不到一個簡單的解釋。我確實找到Herb Sutter's GOTW 49這涉及到專業化問題。我還在stackoverflow上發現了一些問題,但沒有人能真正向我解釋原因,也沒有給我提供好的解決方案。由於轉換錯誤導致的超載/專業化不正確
我有一個類Foo,它可以從一個布爾值構造。我發現(困難的方式)std :: string也可以用bool(false)構造。
我有三個具有不同參數的(模板)方法,如下所示。一個方法接受「任何」模板參數,並接受兩個特化,接受一個結構Foo和另一個接受一個字符串。
#include <string>
#include <iostream>
struct Foo
{
Foo() : value(false){ };
Foo(bool v) : value (v) { }
Foo(const bool& v) : value(v) { }
bool value;
};
template< typename T >
void bar(const T& value)
{
std::cerr << "template bar" << std::endl;
}
template< >
void bar<Foo>(const Foo&)
{
std::cerr << "template bar with Foo" << std::endl;
}
template< typename T >
void bar(const std::string&)
{
std::cerr << "template bar with string" << std::endl;
}
int main(int argc, char* argv[])
{
bar(false); // Succeeds and calls 1st bar(const T&)
bar<Foo>(false); // Crashes, because 2nd bar(const std::string&)
// is called with false promoted to null pointer.
return 0;
}
我已經用Visual Studio 2010和MinGW(gcc 4.7.0)測試過了。 GCC很好地給出了一個編譯警告,但MSVC不會:
main.cpp:34:20: warning: converting 'false' to pointer type for argument 1 of 'std::basic_string< ... ' [-Wconversion-null]
小更新(代碼):即使富明確的專業化不起作用\
小更新2:編譯器不抱怨「模糊超載」。
小小更新3:有些人回答說,Foo的兩個構造函數接受bool
,「無效」Foo的選擇。我只用一個轉換構造函數測試過類似的版本。這些也不起作用。
問題:
- 爲什麼編譯器嘗試調用字符串參數版本?
- 爲什麼在bar()調用中添加
<Foo>
很重要。 - 我該如何防止這種情況發生。例如。當輸入bool時,我可以強制編譯器選擇
bar(const Foo&)
嗎? - 或者,我可以在有人撥打
bar<Foo>(false)
時執行編譯錯誤嗎?
所有四個回答的第一個。謝謝。關於答案1:Foo也可以由false構建......爲什麼它會選擇bar(string)而不是bar(Foo)? –
你在對一個自從被刪除的答案的評論中說,你只從'const bool&'構造函數開始。事情是,我不認爲字面上的'false'是'const bool&'。你可以嘗試評論構造函數出來,看看它是否工作? –
已經嘗試了所有三種組合:兩種構造函數,一種使用bool,另一種使用const bool&。不起作用。 –