我用 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)
then 四个编译器会产生同样的错误。
最后,GCC 和 Clang 接受了代码,我相信它们是正确的。我的推理基于 8.5.3/5
对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化为
— 如果引用是左值引用 [...]
— 否则,[...]引用应为右值引用。
— 如果初始化表达式是[...]函数左值[...]
然后引用绑定到初始化表达式的值[...]
我的解释是否正确(即 Clang 和 GCC 因给定原因而合规)?