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

时间:2013-03-23 17:28:38

标签: c++ function c++11 language-lawyer rvalue-reference

我使用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是否符合给定的原因)?

1 个答案:

答案 0 :(得分:9)

  

我的解释是否正确[...]?

由于您引用的标准段落,您的解释是正确的。关于参考约束的第13.3.3.1.4 / 3段进一步确认:

  

除了隐式对象参数,参见13.3.1,标准转换序列不能   如果它需要绑定除非对非易失性const类型的引用之外的左值引用,则形成   右值或绑定对左值以及函数左值的右值引用。 [...]

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

  

[...]标准转换序列S1是比标准转换序列S2更好的转换序列,如果

     

- [...]

     

- S1和S2是引用绑定(8.5.3),S1将左值引用绑定到函数lvalue ,S2将rvalue引用绑定到函数lvalue 。 [示例

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

- 结束示例]