Search code examples
c++nullimplicit-conversionc++03overload-resolution

NULL implicit pointer conversion causing ambiguous overload


Problematic C++03 code:

#include <cstddef>
struct Foo {
    explicit Foo(const char *){}
    Foo &operator=(const char *) {return *this;}
    Foo &operator=(char) {return *this;}
};
int main() {
    Foo s("foobar");
    s = NULL;
}

Error:

In file included from /opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/cstddef:50,
                 from <source>:1: <source>: In function 'int main()': <source>:9:9: error: ambiguous overload for 'operator=' (operand types are 'Foo' and 'long int')
    9 |     s = NULL;
      |         ^~~~ <source>:4:10: note: candidate: 'Foo& Foo::operator=(const char*)'
    4 |     Foo &operator=(const char *) {return *this;}
      |          ^~~~~~~~ <source>:5:10: note: candidate: 'Foo& Foo::operator=(char)'
    5 |     Foo &operator=(char) {return *this;}
      |          ^~~~~~~~

If I understand correctly, the source of the problem comes from the fact that NULL in C++03 can act as both an integer and a pointer. I am also aware that C++11 and later provide nullptr to solve this problem. Upgrading to C++11 is not an option for me.

Question: how is this problem solved in practice and how can I keep the ability to provide overloads?

One way is to tell the user not to use NULL. Is there a programmatic solution?


Solution

  • A way to achieve it is to use a proxy struct for char, which will make operator=(const char*) preferrable. Like this:

    #include <cstddef>
    
    struct MyChar
    {
        MyChar(char c) : c(c){}
        operator char() {return c;}
        char c;
    };
    
    struct Foo {
        explicit Foo(const char *){}
        Foo &operator=(const char *) {return *this;}
        Foo &operator=(MyChar) {return *this;}
    };
    int main() {
        Foo s("foobar");
        s = NULL;
        s = 'x';
        s = "foo";
    }