右值引用可以绑定到函数吗?

Can an rvalue reference bind to a function?

本文关键字:函数 绑定 引用      更新时间:2023-10-16

我用GCC, Clang, ICC和VS测试了以下代码:

void f() {}
  
void g(void (&&)()) { }
int main() {
    g(f);
}

我们可以看到,g是一个右值引用,而f是一个左值引用,通常,右值引用不能绑定到左值。这正是ICC抱怨的原因:

error: an rvalue reference cannot be bound to an lvalue

VS也给出了一个错误,但原因是:

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

对我来说,这表明VS立即执行函数到指针的转换,而不是直接将引用绑定到f。值得一提的是,如果我将g(f)替换为g(&f),那么这四个编译器会产生相同的错误。

最后,GCC和Clang接受了代码,我相信它们是正确的。我的推理是基于8.5.3/5

对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化为

-如果引用是左值引用[…]

-否则,[…]引用必须是右值引用

-如果初始化表达式是[…][…]

引用绑定到初始化表达式[…]

我的解释是正确的(也就是说,Clang和GCC是兼容的给定原因)?

我的解释正确吗?

是的。

你的解释是正确的,因为你引用了标准的段落。进一步的确认来自第13.3.3.1.4/3段关于引用绑定:

除了隐式对象形参(见13.3.1)外,标准转换序列不能为如果需要绑定左值引用而不是对非易失性const类型的引用,则形成右值或将右值引用绑定到左值而不是函数lvalue。[…]

13.3.3.3/3段包含进一步(间接)确认:

[…如果

,则标准转换序列S1优于标准转换序列S2。

— [...]

—S1和S2是引用绑定(8.5.3),S1将左值引用绑定到函数lvalue, S2将右值引用绑定到函数lvalue。(例子:

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

- 结束示例]