Search code examples
c++pointersreferenceoverload-resolutionconst-reference

function call ambiguity with pointer, reference and constant reference parameter


What I am trying to do is, allow a pointer, reference or constant reference to be passed with the setter function:

class A{
    std::string * p;
    std::string st;

    public:
    A():p(0)
    {}
    A& setS(const std::string& s){
        std::cout<<"called with const std::string&\n";
        st = s;
        p = &st;
        return *this;
    }
    A& setS(std::string& s) {
        std::cout<<"called with std::string&\n";
        p = &s;
        return *this; 
    }
    A& setS(std::string* s) {
        std::cout<<"called with std::string*\n";
        p = s;
        return *this; 
    }
};

int main(){
   std::string s;
   A a;
   a.setS(std::move(s)) //const std::string&
    .setS("")           //const std::string&
    .setS(s)            //std::string&
    .setS(0);           //std::string*
    //if std::string* version is not defined,
    //setS(0) calls the const std::string& version and throws exception 
    return 0;
}

But I have seen that, if the pointer version is not there, the setS(0) calls the const std::string& version of the setS() function.

Is there any ambiguity between the pointer and the reference versions or among any others that matter? Is it well defined and expected to work the same way in all compilers?


Solution

  • There is no ambiguity. When you have A& setS(std::string* s) in the overload set then setS(0) calls the pointer version and 0 is a null pointer. It would be the equivelent of setS(nullptr).

    When A& setS(std::string* s) is not in the overload set then the compiler looks to see if there is a way it can construct a temporary string from 0 and then pass that to A& setS(const std::string& s) since a const& can bind to a temporary. std::string can be constructed from a single pointer and again 0 it tread as a null pointer. So you get a temporary null pointer constructed std::string passed to the const& function.

    This is undefined behavior though. The constructor for std::string requires that the pointer passed to it be a null terminated c string. If it is not then the behavior is undefined.