2016-11-26 38 views
17

右值引用和转发引用之间的区别作出足够清楚在这个例子斯科特迈尔斯:这是一个转发参考?

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, “&&” means rvalue reference (3) 

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

本质上的区别发生时,我们有一个抵扣方面,因此情况(3)明确规定,我们具有vector<...>&&,而情况(4)中的T将被推断并且(在应用参考折叠规则之后)按照“价值类别”进行分类。

但是,有点复杂的模式匹配会发生什么?就拿下面的情况:

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

} 

是什么意思&&这里?

+1

可推论的上下文并不重要。 (3)和(4)都可以推导出来。 – Oktalist

回答

14

在上例中,arg是一个右值引用。

转发参考是一个rvalue参照CV-不合格模板参数

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

(引文从[temp.deduct.call]。)

9

它是一个右值引用,而不是转发参考。

,以确保最简单的方法是尝试通过一个左值,如果失败的话,那么它是一个右值引用,如果没有,那么转发参考:

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 
} 
1

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

什么是转发引用的概念背后是基准运算:

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

让我们模拟编译器模板类型扣除与转发参考

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的实例化可以产生 的函数由左值引用或带参数的函数引用参数右值引用:转发引用是 一个右值引用或一个左值引用,取决于模板类型的扣除。它被命名为这样的,因为在这种情况下,该参数应是作为一个左或作为x值过去了,这是T&& std::forward<T>(T&& a)

的工作,如果你定义一个函数有:

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

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

+0

你确定你的样品?我相信foo(42)和foo(6 * 7)在这里是同一条船:https://godbolt.org/g/jOEK9b – RTempete

+0

@RTempete这篇文章的一部分似乎是错误的:正如你所看到的,两者推导到'int &&' - 相同,而不是'const'。如果Oliv会解释为什么他们认为两者应该是“常量”,并且/或者基于是否涉及(即使在'-O0'表达式中是微不足道的,优化的),也应该存在一些差异,那将会更多有用。 –

+0

对不起,在例程代码中有两个错误。 f(42) - >右值参考和f(6 * 7)。 – Oliv