I am defining multiple overloads of the assignment operator as follows:
Foo.h
class Foo
{
private:
bool my_bool;
int my_int;
std::string my_string;
public:
Foo& operator= (bool value);
Foo& operator= (int value);
Foo& operator= (const std::string& value);
};
Foo.cpp
// Assignment Operators.
Foo& Foo::operator= (bool value) {my_bool = value; return *this;}
Foo& Foo::operator= (int value) {my_int = value; return *this;}
Foo& Foo::operator= (const std::string& value) {my_string = value; return *this;}
And here's my main.cpp (see the comment marked SURPRISE
):
Foo boolFoo;
Foo intFoo;
Foo stringFoo;
// Reassign values via appropriate assignment operator.
boolFoo = true; // works...assigned as bool
intFoo = 42; // works...assigned as int
stringFoo = "i_am_a_string"; // SURPRISE...assigned as bool, not string
std::string s = "i_am_a_string";
stringFoo = s; // works...assigned as string
// works...but awkward
stringFoo = static_cast<std::string>("i_am_a_string");
Question: Can someone tell me why an uncasted string literal is being evaluated in a boolean context?
The C++ standard defines overload resolution rules in chapter 13.3, there you find:
13.3.3.2 Ranking implicit conversion sequences [over.ics.rank]
2 When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)
— a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and
— a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).
This means that the compiler will prefer a standard conversion sequence from the string literal to bool
or int
if available. Now, which standard conversions are relevant? In your case, these two are relevant:
4.2 Array-to-pointer conversion [conv.array]
1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.
This conversion turns the string literal, which is of type const char[N]
, into a const char*
. The second one is:
4.12 Boolean conversions [conv.bool]
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type
bool
. A zero value, null pointer value, or null member pointer value is converted tofalse
; any other value is converted totrue
. A prvalue of typestd::nullptr_t
can be converted to a prvalue of typebool
; the resulting value isfalse
.
That is the reason why the pointer is converted to bool
. Since a standard conversion sequence exists, the user-defined conversion to std::string
is not used.
To solve your problem, I suggest you add another overloaded version that takes const char*
and make it forward the call to the const std::string&
overload.
Daniel is right.
The short answer is that std::string
is not a built-in type and, as such, doesn't get any magical preferential treatment. And that, unfortunately, the type of a string literal such as "hi world"
is not std::string
, but a pointer type which more easily converts to the built-in type bool
than to the "user-defined"† type std::string
.
Basically, the answer is: welcome to C++.
† Yes, I know, it's from the standard library and, no, it doesn't matter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With