admin管理员组

文章数量:1208155

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.)

本文标签: