I’m having trouble understanding how overloads are resolved for operator=(bool)
.
I have the following overloads:
json_variant &operator=(json_variant &&value);
json_variant &operator=(const json_variant &value);
json_variant &operator=(bool value);
json_variant &operator=(double value);
json_variant &operator=(const std::string &value);
json_variant &operator=(std::string &&value);
json_variant &operator=(json_object &&value);
json_variant &operator=(json_array &&value);
The following operation
json_variant v;
v = "abc";
calls the operator=(bool) overload instead of the operator=(const std::string&) overload.
I know there’s an implicit conversion for T* to bool. And there’s also an implicit conversion from const char* to std::string. What I don’t understand, is why this isn’t an ambiguous overload that causes an error.
The result of taking the wrong overload is understandably lethal, and it’s a regrettably easy mistake to make.
I can imagine ugly ways to fix it.
json_variant &operator=(const char*);
json_variant &operator=(char*);
template <typename U>
json_variant&operator=(U*) {
static_assert("This probably isn't what you want.");
}
That operator=(bool) should be so greedy seems like such an ugly behavior that I can’t help thinking I’ve missed something.
>Solution :
One quick and dirty solution that works as far back as C++98 and beyond:
struct foo {
void operator = (bool arg) { }
void operator = (const void *ptr); // not implemented
};
int main()
{
foo f;
f = false; // ok
f = "abc"; // link time error
}
We declare an overload which takes a const void *
pointer. That is a more specific conversion from T *
than bool
, so that overload is selected by the unwanted pointer argument.
But we don’t implement this overload, so if it is used, the program won’t link.
My above little program builds if I comment out the f = "abc"
assignmet, and it also builds if I instead comment out the const void *
overload of the operator =
, because then the bool
overload is selected by that assignment.