我试图了解C ++ 11的通用引用,并编写了以下代码:
#include <cstdio>
template <typename L, typename R>
static void Run(L&& lhs, const R& rhs) {
lhs += rhs;
}
static void Run2(int&& lhs, const int& rhs) {
lhs += rhs;
}
int main() {
int a = 0;
int b = 3;
Run(a, b);
printf("%d\n", a);
// This does not compile.
Run2(a, b);
printf("%d\n", a);
return 0;
}
请注意Run()
有效,但调用Run2()
的行无法编译。我无法弄清楚原因。我得到的错误是no known conversion from 'int' to 'int &&' for 1st argument
。
我确定编译器是正确的,但我无法弄清楚原因。似乎Run()
和Run2()
正在做同样的事情吗?
顺便说一句,将Run2()
更改为使用单个参数进行模板化也不起作用。
答案 0 :(得分:5)
“通用引用”只能在推断引用类型的上下文中发生,例如在模板类型上下文T&&
中。在这种情况下,对于rvalue参数,T可以推导为int
,因此您可以使用int&&
作为参数类型;或者作为您的左值参数的int&
,这将为每个参考折叠规则的类型int& &&
变为int&
。在Run2函数中,类型直接为int&&
,因此除非使用std::move
,否则它不能绑定到任何左值。
答案 1 :(得分:2)
Rvalue引用无法绑定到左值。
创建转发引用的特殊规则是,推导出的模板参数T
在函数参数T = U&
中出现时可以推导为T&&
,这使得函数参数类型为U&
(感谢来自U& &&
的参考资料崩溃)。但是,Run2
的参数类型不是推导出来的,因此第一个参数直接是右值参考。
使用单个模板参数将Run2
更改为函数模板意味着参数推导将失败,因为没有适合两个参数的一致类型集。
答案 2 :(得分:1)
第一个是通用引用(如Scott Meyers Effective Modern C++一书中所述),第二个是右值引用
为了使其正常工作,您需要像这样调用它:
Run2(std::move(a), b);
答案 3 :(得分:1)
Run(a,b)
调用一个函数,其中typename L == int&amp;和R == int
所以
static void Run(L&& lhs, const R& hrs)
是模板实例化为
static void Run(int & && lhs, const int& hrs)
或实际因为参考折叠,它变成
static void Run(int& lhs, const int& hrs)
Run2
需要lhs
的右值引用,它只能从转换中获得或者被赋予一个未命名的变量(临时)。在你的情况下,你可以使用演员来调用函数:
Run(std::move(a), b)