[英]conversion operator overloading ambiguity, compilers differ
我已經看到了關於此的其他問題,但沒有一個完全解釋它。 編譯器處理以下兩種情況的正確方法是什么? 我用gcc 4.7.1(使用-std = c ++ 0x),VS2010和VS2012嘗試了一下,得到了不同的結果:
例1:
struct BB
{
// generic cast
template<typename T>
operator T() const
{
return 0;
}
// string cast
operator std::string() const
{
return string("hello");
}
};
int main()
{
BB b;
string s = b;
}
輸出:
例2:
struct BB
{
// generic cast
template<typename T>
operator T() const
{
return 0;
}
// string cast
operator std::string() const
{
return string("hello");
}
};
int main()
{
BB b;
string s = (string)b;
輸出:
你的第二個版本與C風格的演員是不明確的。 問題是static_cast<std::string>
有兩種方法可以將BB
類的實例轉換為字符串。 顯而易見的路徑是使用非模板std :: string強制轉換運算符直接轉換為字符串。 有一條更加狡猾的道路,除了VS2010以外都發現了它。 另一個路徑是使用模板轉換運算符將BB
轉換為字符串的分配器,然后使用此分配器構造空字符串。
模板轉換操作符是潛在危險的野獸。 您剛剛為編譯器提供了將BB
轉換為任何內容的工具。
你的第一個版本逃避了這個問題,因為std::basic_string(const _Alloc& __a)
是一個顯式的構造函數。 顯式構造函數可以由顯式轉換使用,但不能由隱式轉換使用。 正是這個構造函數加上轉換為創建歧義的分配器,並且此路徑不能與隱式轉換一起使用。
至於為什么VS1012在隱含轉換上失敗,它可能是VS2012中的一個錯誤,或者可能是C ++ 11創建了從BB
到std::string
更多途徑。 我不是C ++ 11專家。 我甚至不是新手。
還有一件事:如果你使用過,你的代碼會失敗得更厲害
std::string s;
s = b;
賦值運算符與模板轉換運算符一起創建了更多從b
到s
。 系統應該將b
轉換為std::string
, char
還是char*
?
結論:您真的應該重新考慮使用模板轉換運算符。
在一些編譯器下失敗的原因是因為他們試圖找出你在做什么的不同長度。 罪魁禍首是模板化的操作員調用。
正如這個SO問題所解釋的那樣,必須顯式調用模板化運算符( b.operator()<std::string>
如果你想調用template<typename T> operator();
),但是,沒有辦法調用你的模板化運算符:
b.operator std::string()<std::string>; //invalid
b.operator std::string <std::string>(); //also invalid, string takes no template arguments
// a bunch more weird syntax constructions...
問題來自於operator
后面的名稱取決於模板參數,因此無法指定它。 gcc和VS2012弄清楚你在做什么,並注意到它們可以適應轉換到模板或明確定義的一個=>模糊的調用。 VS2010沒有這樣做並正在調用其中一個,你可以通過調試找到哪一個。
模板專業化可能在這樣的情況下有所幫助,但是,試圖定義
// string cast
template<>
operator std::string() const
{
return string("hello");
}
將失敗,因為編譯器無法區分該函數與沒有template<>
的常規函數之間的區別。 如果原型中有一些參數它會工作,但operator typename
確實有...
長話短說 - 避免模板轉換運算符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.