什么是通用参考的标准/官方名称?

101*_*010 23 c++ c++11 universal-reference c++14 forwarding-reference

我知道如果声明变量或参数具有T&&某种推导类型的类型T,那么该变量或参数通常被称为通用引用.

Scott Meyers在其最初的演讲"C++ 11中的通用参考"中引入了 通用参考这一术语.但是,我想知道普遍参考的官方/标准术语是什么.

101*_*010 28

概观

众所周知,自C++ 11以来,类型参数T&&称为右值参考 [ ISO/IEC 14882:2011§8.3.2/ p2参考文献[dcl.ref] ].也就是说,除非T是模板参数类型或autotypedef对于一些左值引用类型.

例子:

template<typename T>
void foo(T&& p) { // -> T is a template parameter
  ...
}

auto &&p = expression;
Run Code Online (Sandbox Code Playgroud)

虽然T&&上面的示例中的技术仍然是右值参考,但其行为与常规参数显着不同.

当然,你会问"为什么这个特殊情况没有特殊的语法".答案是&&C++委员会为这个特殊的构造故意重载了语法.然而,他们错过了这个特例的名称.

由于这个特定结构没有明确的名称,Scott Meyers创造了广为人知的术语/名称通用参考文献.

但委员会认为,由于多种原因,这个名称并不合适.因此,建议N4164所作香草萨特,Bjarne的Stroustrup的加布里埃尔杜斯雷斯提出要改变名称转发引用.

转发参考文献的名称在委员会成员之间的非正式讨论中得到了最多的支持,包括前面提到的提案的作者.有趣的是,Scott Meyers本人在他最初的"Universal References"演讲中引入了这个词.然而,后来他决定继续使用名称通用引用.因为这个决定发挥了作用,当时他并不认为转发参考一词也包含在auto&&案例中.

为什么不普遍参考

根据该提议,术语" 通用引用"虽然是一个具有明显含义的合理名称,但它在几个方面恰好是错误的.

一个普遍的基准必然意味着以下几点:

  • 可以在任何地方使用的参考; 要么
  • 可用于所有内容的引用; 要么
  • 相似的东西.

显然情况并非如此,也不适合使用这种结构.此外,这个名称会鼓励许多人认为具有这种名称的东西意味着"普遍"使用.委员会认为这是件坏事.

此外,"通用引用"本身甚至不是真正的引用,而是一组规则,用于在特定上下文中以特定方式使用引用,并为该用途提供某些语言支持,并且该用法是转发.

为什么auto&&还被认为是一个转发案例

auto&&因为它遵循参考折叠规则,所以也被视为前瞻性案例.例如:

  • 形式的通用lambda, [](auto&& x){ … }
  • for形式的循环, for(auto &&i : v) { ... }
  • 最后,一般情况下,auto&&局部变量用于转发.

转发参考的标准措辞

术语转发参考在以下地方的标准草案N4527中提到:

§14.8.2.1/从函数调用中减去模板参数[temp.deduct.call] (Emphasis Mine):

如果P是cv限定类型,则类型推导将忽略P类型的顶级cv限定符.如果P是引用类型,则P引用的类型用于类型推导.甲转发参考是一个rvalue参照CV-不合格模板参数.如果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)

- 结束例子]

§14.8.2.5/ p10从类型[temp.deduct.type]中推导出模板参数:

类似地,如果P具有包含(T)的形式,则将P的各个参数类型列表的每个参数类型Pi与相应的参数类型列表A的相应参数类型Ai进行比较.如果P和A是当获取函数模板的地址(14.8.2.2)或从函数声明(14.8.2.6)中推导出模板参数时,源自演绎的函数类型以及Pi和Ai是顶级参数类型列表的参数如果它是转发参考(14.8.2.1)并且Ai是左值参考,则P和A分别被调整,在这种情况下,Pi的类型被改变为模板参数类型(即,T &&被简单地改变为T).[注意:结果,当Pi是T&&和Ai时X&,调整的Pi将是T,导致T被推断为X&. - 尾注] [示例:

template <class T> void f(T&&);
template <> void f(int&) { } // #1
template <> void f(int&&) { } // #2
void g(int i) {
f(i); // calls f<int&>(int&), i.e., #1
f(0); // calls f<int>(int&&), i.e., #2
}
Run Code Online (Sandbox Code Playgroud)

- 结束示例]如果对应于Pi的参数声明是函数参数包,则将其declaratorid的类型与A的参数类型列表中的每个剩余参数类型进行比较.每个比较推导出后续位置的模板参数.由函数参数包扩展的模板参数包.在部分排序(14.8.2.4)期间,如果Ai最初是一个函数参数包:

  • dcl.ref/6 - 如果`TR`是`int&`,尝试创建类型"*rvalue reference*to`TR`"会创建`TR`.使用"尝试创造"意味着没有*右值参考*实际上在那里发生; 相反,它只是"尝试创建*右值引用*".如果`T`是引用类型,则'T &&`不是右值引用,因为dcl.ref/5不应引用引用.本质上,`TR &&`,其中`TR`是一个引用,在dcl.ref/6之前不是有效的构造(因此没有名称).在dcl.ref/6之后,它意味着`TR` ......也许? (2认同)