C++模板函数的行为

sup*_*uan 18 c++ templates c++11 universal-reference

假设我有这个功能:

bool f(int&& one, int&& two) { }
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用此代码调用它:

int x = 4;
f(x, 5);
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨它不能将x从左值引用转换为右值引用,这是正确的.

现在,如果我将f转换为模板函数,如下所示:

template <class T, class U>
bool f(T&& one, U&& two) { }
Run Code Online (Sandbox Code Playgroud)

然后我可以用左值引用来调用它:

int x = 5;
f(x, 5);
Run Code Online (Sandbox Code Playgroud)

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

mas*_*oud 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
Run Code Online (Sandbox Code Playgroud)

值得标准草案的例子:

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&
Run Code Online (Sandbox Code Playgroud)


Jur*_*aho 8

因为存在模板参数推导,所以会发生引用折叠.这是Scott Meyers所说的普遍参考.该U&&会实际上成了int &.有一篇很好的文章和视频,关于它是如何工作的以及如何使用它.


aar*_*man 6

这是因为在c ++ 11中添加了引用折叠规则

A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&
Run Code Online (Sandbox Code Playgroud)

在模板中应用这些规则但不在正常函数中,通常在函数中没有引用折叠.还有一些其他特定情况,其中引用折叠将发生,如存在auto,decltypetypedef(包括using声明)解释编译的结果.必须在c ++ 11中添加引用折叠,因为否则使用像A&&这样的引用会变成错误,因为您无法引用引用.

  • 虽然参考折叠确实发生在"通用引用"的情况下,真正的魔法发生在此步骤之前并且发生在模板参数推断期间.你关于参考折叠不正常功能的说明是完全错误的; 参考折叠可以在任何地方发生:`使用T = int &&; void foo(T&x);`由于引用崩溃,这里x是一个`int&`. (2认同)