23

在 Scott Meyers 的这个例子中,右值引用和转发引用之间的区别已经很清楚了:

Widget&& var1 = someWidget;     // here, “&&” means rvalue reference (1)

auto&& var2 = var1;             // here, “&&” does not mean rvalue reference (2)

template<typename T>
void f(std::vector<T>&& param); // here, “&amp;&” means rvalue reference (3)

template<typename T>
void f(T&& param);              // here, “&amp;&”does not mean rvalue reference (4)

本质上,当我们有一个可推导的 context时,就会发生区别,因此案例 (3) 明确指出我们有一个vector<...>&&,而T案例 (4) 将被推导并且(在应用参考折叠规则之后)按照“值类别”进行分类。

但是更复杂的模式匹配会发生什么?以以下案例为例:

template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{

}

这里是什么&&意思?

4

3 回答 3

17

在你的最后一个例子中,arg是一个右值引用。

转发引用是对 cv 非限定模板参数的右值引用

并且Tuple<Ts...>不是模板参数。

(引自 [temp.deduct.call]。)

于 2016-11-26T14:00:29.117 回答
11

它是右值引用,而不是转发引用。

最简单的方法是尝试传递一个左值,如果失败,那么它是一个右值引用,如果不是,那么一个转发引用:

template<typename... Ts>
struct foo {};

//f function definition

int main() {
    foo<int, double> bar;
    f(bar); // fails! Cannot bind lvalue to rvalue reference
    f(foo<int, double>{}); // ok, rvalue is passed
}
于 2016-11-26T14:01:15.937 回答
4

转发引用的概念不是一个标准的概念,看到它是有用的,但如果你想正确理解和处理它,你必须理解引用算法。(我相信迈耶的书也有关于它的一章)

转发引用的概念背后是引用算法:

  • && && = &&
  • && & = &
  • & && = &
  • & & = &

让我们用转发引用模拟编译器模板类型推导

template<class T>
void foo(T&&);
//...
const int i=42;
foo(i); // the compiler will defines T = const int &
         //          T&&  = const int & && = const int &
         // => the compiler instantiates void foo<const int &>(const int &);
foo(6*7);// the compiler will defines T = int
         //          T&&  = int &&
         // the compiler instantiates  void foo<int>(int &&);

在这种情况下,模板 foo 的实例化可以产生一个函数,该函数通过左值引用或接受参数右值引用的函数:转发引用是右值引用或左值引用,具体取决于模板类型推导。它是这样命名的,因为在这种情况下,参数应该作为左值或作为 xvalue 传递,这就是T&& std::forward<T>(T&& a)

如果你声明一个函数有:

 template<class T>
 void foo(ATemplateClass<T> && a);

无论编译器为 T 推断出什么类型,您都会得到一个右值引用参数。

于 2016-11-27T23:41:43.093 回答