2013-03-04 62 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列表,它不能存在,其唯一目的是确保在两种模板在编译器不会抱怨的方面有很大不同)。