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