Reputation: 37172
#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;
}
I have overloaded =
operator. I expected f = "this";
statement to call operator=(const string& ss)
overload. But it does not. It calls operator=(bool b)
overload. Why?
Upvotes: 7
Views: 208
Reputation: 13
As others have said, an easy fix to this is to simply cast your string to an std::string
, when doing the operator, so C++ knows exactly which overload to choose:
#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;
}
Upvotes: 0
Reputation: 275330
As noted by another answer, the pointer-to-char to bool
conversion is preferred because it involves no user-defined conversions, while the std::string
conversion has a user-defined conversion in it.
C++11 offers the ability to do manual type control.
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";
}
where we match a type perfectly if it can be converted to a std::string
, and the template doesn't match if it cannot be converted to std::string
and other overloads are looked at.
If you have many types you want to be able to support, you have to use long logical forms that describe which of the overloads you want to run, and make sure the others don't accept it (with the not construct above). If you only have two types, the second type can be a traditional overload. The template overload gets first crack at anything that doesn't match the traditional overload exactly...
(The second template argument is a variardic list of numbered enum
s which cannot exist, whose only purpose is to make sure that the two templates differ in sufficient ways for the compiler not to complain.)
Upvotes: 1
Reputation: 227390
This operator operator=(const string& ss)
requires a conversion of a user defined type for the argument (const char*
to std::string
), whereas the bool
version has none and so provides a better match: you get the conversions from built-in types const char[5]
to const char*
to bool
.
Upvotes: 13
Reputation: 401
Without delving into C++ standards, on the surface your problem is, you defined your assignment overload with string& and a bool but in your test you're assigning a char* array.
So if you define a string and assign, it will work as expected.
Check it working here : http://codepad.org/owb6noXR
Upvotes: 0