0

I'm learning the rvalue reference concept in c++.

When testing the following code, I found the "fun" was called despite it not using fun(abc &&) to accept the temporary object(prvalue).


class abc
{
};
void fun(abc &)
{
    cout << 1111111 << endl;
}
void main()
{
    fun(abc());
}

output: 1111111

If this is allowed due to temporary materialisation

Why does the following code fail to compile?

void fun(int &)
{
    cout << 1111111 << endl;
}
void main()
{
    fun(5);
}

Output: Compiler error!

many thanks

Anning Wuwang
  • 333
  • 1
  • 8
  • 3
    No, the first code sample won't compile either. It's essentially the same error as the second example. – cigien Jun 01 '20 at 23:12
  • That shouldn't compile. If it does, I recommend adding the compiler and version number to the question. Someone might recognize what you've run into and be able to point you at a bug report or similar. – user4581301 Jun 01 '20 at 23:20
  • 2
    MSVC has allowed this sort of thing by default for a long time, although it's forbidden by the language. If you're using MSVC, be sure to try the `/permissive-` compiler flag to get better standards compliance for this and other differences. – aschepler Jun 02 '20 at 00:02
  • @aschepler The flag fixed it! Thank you very much for the spot-on answer :) – Anning Wuwang Jun 02 '20 at 12:12

2 Answers2

1
void fun(int &)
{
    cout << 1111111 << endl;
}
void main()
{
    fun(5);
}

doesnt compile because you cannot pass a reference to a literal to a function that expects a reference to a modifiable variable. Although you dont change it, you might

this works

void fun(const int &)
{
    cout << 1111111 << endl;
}
void main()
{
    fun(5);
}
pm100
  • 48,078
  • 23
  • 82
  • 145
1

The reason why both fail to compile is that temporaries cannot be bound to non-const references.

In the first case, the expression abc() constructs a temporary abc object. Trying to pass it to fun() tries to bind the temporary to a non-const reference; this is disallowed.

The second case is effectively the same thing: the compiler tries to use 5 to construct an int temporary, but then fails to bind it to the non-const reference.

int const & a = 5; // allowed
int & b = 5;       // disallowed

This was an intentional design decision, intended to prevent what would otherwise be very easy mistakes to make. Let's pretend this rule doesn't exist:

void add_one(double & i) {
    i += 1;
}

void something() {
    int x = 5;
    add_one(x);
    std::cout << x;
}

Wait... why is x 5 instead of 6!? Because x was used to construct a double temporary, which bound to the reference argument. add_one() added 1 to the temporary. Then the temporary is destroyed when control returns to something() and the value of x was never changed.

But, since temporaries cannot bind to non-const references, the add_one(x) line will instead fail to compile. This saves the programmer from having to figure out that an invisible temporary was implicitly created and destroyed on that one line of code.

cdhowie
  • 158,093
  • 24
  • 286
  • 300