18

假设我有这个功能:

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);

为什么会这样?为什么编译器在这种情况下不抱怨?

4

3 回答 3

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&
于 2013-10-03T07:28:40.217 回答
8

因为有模板参数推导,所以会发生引用折叠。这就是 Scott Meyers 所说的通用参考。将U&&实际上成为int &。有一篇很好的文章和视频介绍了它的工作原理以及如何使用它。

于 2013-10-03T07:31:48.957 回答
6

发生这种情况是因为在 c++11 中添加了引用折叠规则

A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&

在模板中应用了这些规则,但在普通函数中没有应用,在函数中没有正常折叠的引用。还有一些其他特定情况会发生引用折叠,例如存在auto,decltype或 a typedef(包括using声明),这解释了编译结果。必须在 c++11 中添加引用折叠,否则使用 A & & 之类的引用会出错,因为您无法获得对引用的引用。

于 2013-10-03T07:28:27.880 回答