I don’t understand why this code compiles and runs:
std::string s;
std::cin >> s;
// if (s == "done") { // version 1
if ("done" == s) { // version 2
std::cout << "We're done here" << std::endl;
}
Version 1 works as I would expect. The compiler sees that s
is a std::string
, and uses the std::string
definition of ==
to do the comparison.
However, when comparing a variable to an explicit value, I like to use the trick of putting the explicit value first in case one day I accidentally use =
instead and do an assignment instead. Hence, version 2.
Now version 2 works on my compiler (llvm on MacOS) the same way as version 1, but I’m not sure why (or if it’s a reliable result). I would have though that the compiler sees "done" as a char*
explicit constant and says, "hey, ==
makes no sense on char*" and give me a compilation error message. But my compiler doesn’t do that, it compiles without complaint and the code executes the same way as version 1.
What am I misunderstanding here?
>Solution :
The type of "done"
is not char*
. It is const char[5]
.
But in any case, it works because if you include <string>
, which you must have to use std::string
, then (before C++20) you include an overload for operator==
of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
const CharT* rhs );
and one of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const CharT* lhs,
const std::basic_string<CharT,Traits,Alloc>& rhs );
See https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp for reference.
std::string
is just std::basic_string
with CharT
being char
and Traits
and Alloc
being some defaults that don’t matter here.
So effectively one overload accepts a const std::string&
as left-hand argument and const char*
as right-hand argument, and the other accepts the reverse.
const char[N]
can be deduced as const char*
and it is implicitly convertible to the latter for every N
, so the first overload is viable for s == "done"
and the second for "done" == s
.
The standard library is written with these overloads specifically so that your use will work. Your approach of using the "done" == s
variant makes sense, because "done" = s
would indeed be an error. operator=
can only be overloaded with a class type on the left-hand side.
Since C++20, the overloads look a bit different. In particular it isn’t necessary to have both anymore. The compiler now automatically tries overloads matching the rewritten expression with reversed operands of ==
when doing overload resolution.
to an explicit value,
explicit constant
I am not sure what you mean here, but "explicit value" and "explicit constant" are not standard terminology. Probably you mean "(string) literal" instead.
and says, "hey, == makes no sense on char*"
It doesn’t work that way. As soon as either side of ==
is a class type, the compiler has to consider that ==
may be overloaded to match the expression.