Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange operator overloading behavior?

#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?

like image 265
Pratik Deoghare Avatar asked Mar 04 '13 21:03

Pratik Deoghare


People also ask

What is the example of operator overloading?

Operator Overloading in C++ This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. For example, we can overload an operator '+' in a class like String so that we can concatenate two strings by just using +.

Can we change the Behaviour of overloaded operator?

Operators play an important role in computer programming. By using it, you can change the behavior of an operator based on the types of its arguments.

What is function overloading and operator overloading with example?

Function overloading means using a single name and giving more functionality to it. Operator overloading means adding extra functionality for a certain operator. When an operator is overloaded, the operator has different meanings, which depend on the type of its operands.


2 Answers

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.

like image 174
juanchopanza Avatar answered Sep 23 '22 02:09

juanchopanza


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 enums which cannot exist, whose only purpose is to make sure that the two templates differ in sufficient ways for the compiler not to complain.)

like image 21
Yakk - Adam Nevraumont Avatar answered Sep 23 '22 02:09

Yakk - Adam Nevraumont