一个右值引用绑定到一个函数? [英] Can an rvalue reference bind to a function?
问题描述
我用GCC,Clang,ICC和VS测试了以下代码:
void f(){}
void g(void(&&)()){}
int main(){
g(f);
}
正如我们所看到的, g
采用右值引用,但 f
是一个左值,一般来说,右值引用不能绑定到左值。这正是ICC抱怨的 :
错误:右值引用不能绑定到左值
VS也会发生错误,但是出于其他原因:
错误C2664:'void h(void(__cdecl&&)(void))'无法将参数1从'void(__cdecl * )(void)'to'void(__cdecl&&)(void)'
对我来说VS正在立即执行一个函数到指针的转换,而不是直接绑定到 f
的引用。值得一提的是,如果我用 g(& f)
替换 g(f)
,那么四个编译器非常相同的错误。
最后, GCC和Clang接受代码,我相信它们是正确的。我的推理基于8.5.3 / 5
对类型cv1 T1的引用由类型cv2 T2 as
- 如果引用是一个左值引用[...] ..] 引用应为右值引用。
- 如果初始化器表达式是 [...] 函数值 [...]
那么引用绑定到初始化器表达式的值 [...]
是我的解释正确[...]。
$ b 您的解释是正确的,因为您引用的标准的段落。进一步的确认来自关于引用绑定的第13.3.3.1.4 / 3段: 除了隐式对象参数,参见13.3 .1,如果需要将除了对非易失性const类型的引用之外的其他lvalue引用绑定到 第13.3.3.2/3段包含进一步(间接)确认:
an rvalue 或者将右值引用绑定到左值,标准转换序列不能为
函数lvalue 之外的 [...]
[...]标准转换序列S1是比标准转换序列S2更好的转换序列,如果
[...]
- S1和S2是参考绑定(8.5.3),S1绑定一个左值引用到函数左值,S2绑定右值引用函数lvalue 。 [示例:
int f(void(&)()); //#1
int f(void(&&)()); //#2
void g();
int i1 = f(g); // calls#1
- end example ] b $ b
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)?
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 ]
这篇关于一个右值引用绑定到一个函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!