假设我有这个功能:
bool f(int&& one, int&& two) { }
如果我尝试使用此代码调用它:
int x = 4;
f(x, 5);
编译器会抱怨它无法将x从左值引用转换为右值引用,这是正确的。
现在,如果我将f转换为这样的模板函数:
template <class T, class U>
bool f(T&& one, U&& two) { }
然后我可以用左值引用来调用它:
int x = 5;
f(x, 5);
为什么会这样?为什么编译器在这种情况下不抱怨?
答案 0 :(得分:10)
根据§8.3.3/ 6.这是参考折叠规则。
template <class T> void func(T&&) // Accepts rvalue or lvalue
void func(T&&) // Accepts rvalue only
void func(T&) // Accepts lvalue only
值得标准草案的例子:
int i;
typedef int& LRI;
typedef int&& RRI;
LRI& r1 = i; // r1 has the type int&
const LRI& r2 = i; // r2 has the type int&
const LRI&& r3 = i; // r3 has the type int&
RRI& r4 = i; // r4 has the type int&
RRI&& r5 = 5; // r5 has the type int&&
decltype(r2)& r6 = i; // r6 has the type int&
decltype(r2)&& r7 = i; // r7 has the type int&
答案 1 :(得分:8)
因为存在模板参数推断,所以会发生参考折叠。这是Scott Meyers所说的通用引用。 U&&
实际上会成为int &
。关于它如何工作以及如何使用它有一个很好的article and video。
答案 2 :(得分:6)
这是因为在c ++ 11中添加了参考折叠规则
A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&
在模板中应用这些规则但不在正常函数中,通常在函数中没有引用折叠。还有一些其他特定情况会发生引用崩溃,例如出现auto
,decltype
或typedef
(包括using
声明)这会解释您的结果汇编。必须在c ++ 11中添加引用折叠,因为否则使用像A&amp; A这样的引用。 &安培;因为你不能引用引用而会出错。