Reputation: 367
While studying C++ I have come across the complex topic of conversion sequences and I have encountered a problem that I couldn't solve on my own.
void g(const double)
{
std::cout << "void g(const double)" << std::endl;
}
void g(const double&&)
{
std::cout << "void g(const double&&)" << std::endl;
}
int main(int argc, char **argv)
{
g(3.14);
return (0);
}
---------------------------- Second example ----------------------------
void g(const double)
{
std::cout << "void g(const double)" << std::endl;
}
void g(const double&)
{
std::cout << "void g(const double&)" << std::endl;
}
int main(int argc, char **argv)
{
g(3.14);
return (0);
}
In this two examples the compiler complains about the fact that the call of the overloaded function "g(double)" is ambiguous.
void g(const double&&)
{
std::cout << "void g(const double&&)" << std::endl;
}
void g(const double&)
{
std::cout << "void g(const double&)" << std::endl;
}
int main(int argc, char **argv)
{
g(3.14);
return (0);
}
But in this example the program compiles properly and prints out "void g(const double&&)". So I don't get why the compiler complains about the first two examples but doesn't about the third.
Upvotes: 2
Views: 1425
Reputation: 13790
This table summarizes who can go where:
---------------------------------------------------------------------------------
Caller | lvalue | const lvalue | rvalue | const rvalue
Function | | | |
---------------------------------------------------------------------------------
[a] f(X& x) | V (1) | | |
---------------------------------------------------------------------------------
[b] f(const X& x) | V (2) | V | V (3) | V (2)
---------------------------------------------------------------------------------
[c] f(X&& x) | | | V (1) |
---------------------------------------------------------------------------------
[d] f(const X&& x) | | | V (2) | V (1)
---------------------------------------------------------------------------------
Upvotes: 5
Reputation: 141618
In overload resolution, direct reference binding is an identity conversion (even if qualifiers are added); it's no better or worse for a double
to match a parameter of double
or reference-to-double
.
The const
is somewhat of a red herring in your examples. For a non-reference type, f(const double)
, the top-level const
is not part of the function signature; and in f(const double&)
, it is still direct binding and so still the identity conversion.
So, your first 2 cases are both identity conversions in both cases and no reason to prefer one or the other.
In case 3, rule C++14 [over.ics.rank]/3.1.3 applies:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
- [...]
- S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
This rule allows functions to be overloaded for rvalues and lvalues of the same type.
Upvotes: 3