2013-03-04 81 views
7
#include <iostream> 
using namespace std; 

class Foo{ 

     string _s; 
     public: 
     Foo(string ss){ 
       _s = ss; 
     } 
     Foo& operator=(bool b){ 
       cout << "bool" << endl; 
       return *this; 
     } 
     Foo& operator=(const string& ss){ 
       cout << "another one" << endl; 
       return *this; 
     } 
}; 


int main(){ 

     Foo f("bar"); 
     f = "this"; 
     return 0; 

} 

我已重載=運算符。我預計f = "this";聲明致電operator=(const string& ss)過載。但事實並非如此。它稱爲operator=(bool b)過載。爲什麼?奇怪的運算符重載行爲?

回答

13

此操作operator=(const string& ss)需要用戶定義類型的參數(const char*std::string)的轉換,而bool版本有沒有,因此提供了一個更好的匹配:您從內置類型const char[5]得到轉換到const char*bool

+0

什麼?超負荷中只有一個UDT。 (除此之外,100%正確) – 2013-03-04 21:50:00

+0

@MooingDuck是的,你是對的。當我沒有想到地鍵入答案時,這是有道理的! – juanchopanza 2013-03-04 21:50:56

+1

+1:這可能會讓新手感到驚訝,因爲The Standard定義的類型將被歸類爲**用戶**定義的類型,但是您去了! – Johnsyweb 2013-03-05 00:42:43

0

沒有深入研究C++標準,表面上你的問題是,你用字符串&和bool定義了你的賦值超載,但是在你的測試中你要分配一個char *數組。

所以,如果你定義一個字符串並賦值,它將按預期工作。

檢查它在這裏工作:http://codepad.org/owb6noXR

+1

另一種解決方法是從調用者那裏除去責任,這裏是:http://liveworkspace.org/code/6UxaG$1但是這並沒有真正回答***爲什麼那個特定的超載被調用的問題。 – Johnsyweb 2013-03-04 21:57:59

0

正如其他人所說,一個簡單的辦法來,這是簡單的字符串強制轉換爲std::string,做運營的時候,所以C++知道到底是哪超載選擇:

#include <iostream> 
using namespace std; 

class Foo{ 

     string _s; 
     public: 
     Foo(string ss){ 
       _s = ss; 
     } 
     Foo& operator=(bool b){ 
       cout << "bool" << endl; 
       return *this; 
     } 
     Foo& operator=(const string& ss){ 
       cout << "another one" << endl; 
       return *this; 
     } 
}; 


int main(){ 

     Foo f((string)"bar"); 
     f = (string)"this"; 
     return 0; 

} 
+1

正如我評論另一個答案,一個替代解決方案,從調用者中刪除責任是[這裏](http://liveworkspace.org/code/6UxaG$1),但這並沒有真正回答***爲什麼的問題***特定的超載被調用。 – Johnsyweb 2013-03-05 00:41:02

1

如由另一個答案所指出的,優選的指針到炭到bool轉換,因爲它不涉及用戶定義的轉換,而轉換std::string中有一個用戶定義的轉換。

C++ 11提供了手動類型控制的功能。

template<size_t n> 
struct enumarated_enum { 
private: 
    enum empty {}; 
}; 

template<bool b, size_t n=0> 
using EnableIf = typename std::enable_if< b, typename enumerated_enum<n>::empty >::type; 

template<typename String, EnableIf< std::is_convertible< String, std::string >::value >... > 
Foo& operator=(String&& s) { 
    cout << "string overload" << "\n"; 
} 

// either this: 
template<typename Bool, EnableIf< !std::is_convertible< Bool, std::string >::value && std::is_convertible< Bool, bool >::value, 1 >... > 
Foo& operator=(Bool&& b) { 
    cout << "bool overload" << "\n"; 
} 
// or this: 
Foo& operator=(bool b) { 
    cout << "bool overload" << "\n"; 
} 

,我們完全一種匹配,如果它可以被轉換爲std::string,和模板不匹配,如果它不能被轉換爲std::string和其他重載的看着。

如果您希望能夠支持多種類型,則必須使用描述要運行哪個重載的長邏輯形式,並確保其他人不接受它(使用not構造以上)。如果您只有兩種類型,第二種類型可能是傳統的過載。模板超載得到第一條裂縫在任何不完全匹配傳統的過載...

(第二個模板參數是編號enum s的variardic列表,它不能存在,其唯一目的是確保在兩種模板在編譯器不會抱怨的方面有很大不同)。