为什么添加`const`使通用引用成为rvalue

RaG*_*__M 23 c++ templates c++11 c++14 forwarding-reference

我一直在阅读Scott关于c ++ 11和14的最后一篇大师文章中的通用引用,尽管有一个参数分配给左值或右值类型的参考参数,但在它们之间存在一些被称为通用引用的东西,它可以推导出来l/rvalue基于传递的参数的类型特征.我可以理解是什么使得参数成为通用引用但是我不清楚的一个原因是为什么在类型参数中添加const const T&& p使得p为rvalue:

template<typename T>
void f(T&& param); // param is an universal reference

template<typename T>
void f(const T&& param); // param is an rvalue reference
Run Code Online (Sandbox Code Playgroud)

const分配给参考参数时,是否会执行此操作.

Tem*_*Rex 17

官方名称不是通用参考,而是转发参考.该标准规定,只有右值引用CV-不合格模板参数属于这一类:

14.8.2.1从函数调用中减去模板参数[temp.deduct.call]

3如果P是cv限定类型,则类型推导将忽略P类型的顶级cv限定符.如果P是引用类型,则P引用的类型用于类型推导.转发引用是对cv-unqualified模板参数的rvalue引用.如果P是转发引用且参数是左值,则使用类型"对A的左值引用"代替A来进行类型推导.[例如:

template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
               // would bind an rvalue reference to an lvalue
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

允许const T&&表现为转发引用,将使得仅将rvalue引用作为参数的模板函数重载成为不可能.

更新:正如@HowardHinnant在评论中提到的,const T&&确实有其用途(另请参阅此问答).

  • 关于原因的更多动机:有时我们需要说:不要绑定到右值,只能绑定到左值:`template <class T> void cref(const T &&)= delete;`. (3认同)
  • "允许const T &&表现为转发引用,会导致绑定rvalue引用lvalues."严格来说,这不是真的.如果允许`const T &&`用作转发引用,我们会在`g(i)`中将`T`推导为`int &`,然后折叠为`const int&`,它将const lvalue refere绑定到lvalue.问题是如果允许'T &&`和`const T &&`作为转发引用,我们就无法重载只接受rvalue引用作为参数的模板函数. (3认同)
  • @TemplateRex你能否展示一个简短的例子(代码),说明为什么"允许const T &&表现为转发引用,会使得只能将rvalue引用作为参数的模板函数重载"?谢谢. (3认同)
  • 为了回到_Effective Modern C++_中第24条混淆OP的部分,Scott(松散地)将通用引用描述为右值引用_在类型推导上下文中_。上面14.8.2.1标准引用中的第一句(非强调)(_"If P is a cv-qualified type, the top level cv-qualifiers of P's type ** are denied for type deduction**"_)解释了 Scott 的声明,即_“即使是一个简单的 `const` 限定符也足以使引用失去普遍性”_(引自书籍,第 24 条)。 (2认同)