6

I'm encountering an unexpected behavior in my code when calling overloaded functions with different rvalue reference types. The code snippet below demonstrates the issue:

#include <iostream>

void foo(int&& x)
{
    std::cout << "int Rvalue: " << x << std::endl;
}

void foo(float&& x)
{
    std::cout << "float Rvalue: " << x << std::endl;
}

int main()
{
    int int_x = 1;
    float float_x = 5.14f;

    foo(int_x);
    foo(float_x);
}

Output

float Rvalue: 1
int Rvalue: 5

Instead of getting the anticipated output, which should be "int Rvalue: 1" and "float Rvalue: 5", I observe the reverse order. I find this behavior perplexing and would appreciate insights into why this is happening.

I have made sure to understand the concept of rvalue references and how overloading works based on them. I have also tried to search for similar issues, but haven't found any that directly address this specific situation.

Any guidance or explanations would be greatly appreciated. Thank you in advance for your assistance!

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 1
    @dmedine && is not a reference to a reference. It's rvalue reference since C++11, take a look at the tags. – 273K Jun 30 '23 at 02:36
  • @dmedine This code [compiles](https://godbolt.org/z/7xWPxjEe3). – Evg Jun 30 '23 at 02:37

1 Answers1

4

Lvalue can't be bound to rvalue-reference, that means for foo(int_x);, void foo(int&& x) won't be called. int could be converted to float, the converted temporary float is an rvalue and could be bound to rvalue-reference, as the result void foo(float&& x) is called.

Similarly for foo(float_x);, void foo(int&& x) is called.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Why can't `int` be converted into a temporary `int`? – Evg Jun 30 '23 at 02:43
  • @EvgsupportsModeratorStrike I think just because *lvalue can't be bound to rvalue-reference* rule takes effect in the first place; which guarantee that `foo(int_x);` won't be called on `void foo(int&& x)` under any circumstances. – songyuanyao Jun 30 '23 at 02:50
  • 3
    This has to be one of the most counter-intuitive examples of rvalue binding there is as the compiler jumps through conversion hoops to produce an rvalue. But logical outcome given it can't bind to lvalues (anything with a name) – doug Jun 30 '23 at 02:50
  • 1
    For reference: The relevant standard sections are [12.4.4.2.5 Reference binding (3)](https://timsong-cpp.github.io/cppwp/n4868/over.ics.ref#3) and [12.4.3 Viable functions (4)](https://timsong-cpp.github.io/cppwp/n4868/over.match.viable#4). - tl:dr: Binding lvalues to rvalue-parameters is not allowed (except if the lvalue is a function), and binding rvalues to non-const lvalue-parameters is also not allowed (but const lvalue-parameters would be ok). If this condition is not met then the function is deemed not viable, so overload resolution can never result in that function being called. – Turtlefight Jun 30 '23 at 03:28