The following overloads are ambiguous (in C++23 GCC 14.2):
#include <utility>
void foo(int num) {}
void foo(int&& num) {}
int main() {
foo(5);
// error: call of overloaded 'foo(int)' is ambiguous
// note: candidate: 'void foo(int)'
// note: candidate: 'void foo(int&&)'
// same with a move:
int x = 5;
foo(std::move(x));
// error: call of overloaded 'foo(std::remove_reference<int&>::type)' is ambiguous
// ...
}
I expected that foo(int&&)
would take precedence over foo(int)
when the function is called with an rvalue. For example, if you look at the opposite situation: no overloads, only foo(int&&)
is declared, and you call it on an lvalue foo(x)
. It won't compile because rvalue reference int&&
cannot bind lvalue int
. Since foo(int&&
) is a narrower case than foo(int)
, then foo(int&&)
should be preferred in the overloaded situation for the rvalue case.
What is the semantic reason why foo(int&&)
should not have a higher priority in this overload resolution? Maybe it just does not make sense to bother with such an overload at all?
As far as I understand, both cases int
and int&&
are semantically the same inside the foo(...)
function body. I.e. in both cases the parameter num
is a temporary (on the stack) lvalue in the function body, not a reference to something the user of foo
cares about. So, there is no point to have different function bodies. The difference is in the interface for the user: whether the user cares about an object and wants to pass a copy of it, or no. But then, if you want to cover both cases of int
and int&&
arguments, you can just use foo(int)
. There is no need for an overload. And if you want to narrow it down, you have foo(int&&)
. (The notion of a "copies only" parameter that cannot bind rvalues does not make much sense.)