2014-12-25 37 views
3

此代碼失敗,但我認爲選擇的轉換函數應該是operator std::string(),因爲它的步驟(Foo -> std::string)比operator const char*()Foo -> const char* -> std::string)要少。爲什麼這個用戶定義的轉換失敗?

struct Foo 
{ 
    operator const char*(); 
    operator std::string(); 
}; 

void f(Foo foo) 
{ 
    std::string s2(foo); // Error! 
} 

標準說這種轉換僅限於一個轉換序列,以及轉換應用於他們明確只在,那麼,爲什麼這些失敗?

的錯誤是:

error: call to constructor of 'std::string' (aka 'basic_string<char>') is ambiguous 
    std::string s2(foo); 
       ^~~~ 
note: candidate constructor 
     basic_string(basic_string&& __str) 
    ^
note: candidate constructor 
     basic_string(const basic_string& __str); 
    ^
note: candidate constructor 
     basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()); 
    ^
1 error generated. 

回答

3

要使用唯一的非顯性的構造函數和用戶定義的轉換,你應該從foocopy-initializings2,而不是direct initializing它。從cppreference

直接初始化報價比複製的初始化更加寬容:複製初始化僅考慮非顯式構造函數和用戶定義的轉換功能,而直接初始化考慮所有構造函數和隱式轉換序列。

試試這個:

std::string s2 = foo; 

您現有的代碼調用的std::string構造,與Foo類型的對象。由於存在從foo到多個std::string構造函數的參數類型的有效轉換,並且轉換序列長度相同,所以會遇到模糊問題。

+0

@remyabel但是,如果我做'的std :: string S2 = foo' ... –

+0

@Template哎呀,我是編譯錯誤的代碼它的工作原理。 –

0

錯誤是相當清楚的。生成錯誤的行包含std::string實例的構造函數,該實例具有使用const char*std::string&拷貝構造函數的有效構造函數。兩者都需要使用您提供的轉換過載的單個隱式轉換步驟,因此它意味着哪一個模糊不清。

顯式轉換對象調用預期的轉換 - 這取決於你的內部邏輯const char*構造可能是「便宜」,因爲std::string轉換可能只是返回std::string((const char*)this)反正。如果是這種情況,我甚至建議刪除std::string轉換器,因爲它總是會導致永遠不會表現更多的歧義。

+0

在另一方面,'的std :: string'轉換操作符返回一個可用於布展施工或-assignment右值,所以性能不應該是一個問題,而'的std :: string'轉換運算符避免了返回的指針值的生命週期的任何可能的複雜性,所以我個人建議刪除'const char *'轉換運算符。 – hvd

1

那麼,兩者的轉化需要一個步驟:

  • foo - >char const*使用std::string::string(char const*)
  • foo - >std::string使用std::string::string(std::string&&)

第三過載是一個選項過載結果需要考慮,但構造函數採取std::string&&是比一個採取std::string(std::string const&),並將被選中,如果他們是唯一的選擇。

目前我不能輕易地測試,但我預計

std::string s3 = foo; 

將通過std::string喜歡的轉換。

+0

這真的很有幫助 – RicardoE