I have a class with an implicit const char * constructor. My intuition tells me that it shouldn’t matter whether I implicitly or explicitly invoke the constructor, but apparently it does matter in the case of const char * and I don’t understand why. The VC++ compiler matches foo(const String &t) for the first call to foo in the code below:
struct Str
{
Str(const char *c)
{
value = c[0];
}
Str(double c)
{
value = char(c);
}
char value;
};
void foo(const Str &t)
{
cout << "const Str &t matched\n";
}
void foo(const Str &&t)
{
cout << "const Str &&t matched\n";
}
void main()
{
foo("v");
foo(Str("v"));
foo(5.0);
foo(Str(5.0));
}
It matches the Str &&t version of foo for everything else. Why does it behave differently in the implicit “v” case? And what should I change to get the && version of foo to match? (imagine foo is for example a vector::push_back function — I would rather not have to explicitly cast all my string literals.)
It’s a known issue with the specification of rvalue references, which is now fixed but wasn’t discovered when MSVC10 implemented theirs. Basically, when deciding whether to bind to lvalue or rvalue references, the original lvalueness or rvalueness of the argument is considered, not after any conversions might take place if they are required. This is because the original rvalue references were too greedy about binding to lvalues and some strong wording was put in place to ensure the safety of rvalue references, but it turned out to be a little over-zealous. You don’t need a custom type to demonstrate this- a simple
std::stringwill do fine.