Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an rvalue reference bind to a function?

I tested the following code with GCC, Clang, ICC and VS:

void f() {}
  
void g(void (&&)()) { }

int main() {
    g(f);
}

As we can see, g takes an rvalue reference but f is an lvalue and, in general, rvalue references cannot be bound to lvalues. That's exactly what ICC complains about:

error: an rvalue reference cannot be bound to an lvalue

VS also gives an error but for another reason:

error C2664: 'void h(void (__cdecl &&)(void))' : cannot convert parameter 1 from 'void (__cdecl *)(void)' to 'void (__cdecl &&)(void)'

This suggests to me that VS is immediately performing a function-to-pointer conversion rather than directly bind the reference to f. It's worth mentioning that if I replace g(f) with g(&f) then the four compilers yield this very same error.

Finally, GCC and Clang accept the code and I believe they are correct. My reasoning is based on 8.5.3/5

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as

— If the reference is an lvalue reference [...]

— Otherwise, [...] the reference shall be an rvalue reference.

     — If the initializer expression is a [...] function lvalue [...]

     then the reference is bound to the value of the initializer expression [...]

Is my interpretation correct (that is, Clang and GCC are compliant for the given reason)?

like image 955
Cassio Neri Avatar asked Mar 23 '13 17:03

Cassio Neri


People also ask

Can lvalue bind to rvalue reference?

An lvalue reference can bind to an lvalue, but not to an rvalue.

Can a function return an rvalue?

Typically rvalues are temporary objects that exist on the stack as the result of a function call or other operation. Returning a value from a function will turn that value into an rvalue. Once you call return on an object, the name of the object does not exist anymore (it goes out of scope), so it becomes an rvalue.

What is the purpose of an rvalue reference?

Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

Can rvalue be const?

So an rvalue can be used both with rvalue overloads and a const lvalue reference.


1 Answers

Is my interpretation correct [...]?

Yes.

Your interpretation is correct because of the Paragraph of the Standard that you quoted. A further confirmation comes from Paragraph 13.3.3.1.4/3 on reference binding:

Except for an implicit object parameter, for which see 13.3.1, a standard conversion sequence cannot be formed if it requires binding an lvalue reference other than a reference to a non-volatile const type to an rvalue or binding an rvalue reference to an lvalue other than a function lvalue. [...]

Paragraph 13.3.3.2/3 contains a further (indirect) confirmation:

[...] 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 S1 binds an lvalue reference to a function lvalue and S2 binds an rvalue reference to a function lvalue. [ Example:

int f(void(&)()); // #1
int f(void(&&)()); // #2
void g();
int i1 = f(g); // calls #1

end example ]

like image 177
Andy Prowl Avatar answered Sep 23 '22 00:09

Andy Prowl