这是转发参考吗?
Is this a forwarding reference?
右值引用和转发引用之间的区别在 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, “&&” means rvalue reference (3)
template<typename T>
void f(T&& param); // here, “&&”does not mean rvalue reference (4)
本质上,区别发生在我们有一个可推导的上下文时,因此情况(3)明确指出我们有一个vector<...>&&
,而T
在情况 (4) 将被推导并(在应用引用折叠规则之后)根据 "value category" 进行分类。
但是稍微复杂一点的模式匹配会发生什么呢?以下面的例子为例:
template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{
}
这里的&&
是什么意思?
在你的最后一个例子中,arg
是一个右值引用。
A forwarding reference is an rvalue reference to a cv-unqualified template parameter
并且Tuple<Ts...>
不是模板参数。
(引自 [temp.deduct.call]。)
它是右值引用,不是转发引用。
最简单的方法是尝试传递左值,如果失败,则为右值引用,否则为转发引用:
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
}
转发引用这个概念不是一个标准的概念,看到它就知道是很有用的,但是要想正确理解和处理它,就必须了解引用算法。 (我相信Meyer的书中也有一章讲到)
转发引用的概念背后是引用算法:
- && && = &&
- && & = &
- & && = &
- & & = &
让我们用转发引用来模拟编译器模板类型推导
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 推导出什么类型,您都会得到一个右值引用参数。
右值引用和转发引用之间的区别在 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, “&&” means rvalue reference (3)
template<typename T>
void f(T&& param); // here, “&&”does not mean rvalue reference (4)
本质上,区别发生在我们有一个可推导的上下文时,因此情况(3)明确指出我们有一个vector<...>&&
,而T
在情况 (4) 将被推导并(在应用引用折叠规则之后)根据 "value category" 进行分类。
但是稍微复杂一点的模式匹配会发生什么呢?以下面的例子为例:
template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{
}
这里的&&
是什么意思?
在你的最后一个例子中,arg
是一个右值引用。
A forwarding reference is an rvalue reference to a cv-unqualified template parameter
并且Tuple<Ts...>
不是模板参数。
(引自 [temp.deduct.call]。)
它是右值引用,不是转发引用。
最简单的方法是尝试传递左值,如果失败,则为右值引用,否则为转发引用:
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
}
转发引用这个概念不是一个标准的概念,看到它就知道是很有用的,但是要想正确理解和处理它,就必须了解引用算法。 (我相信Meyer的书中也有一章讲到)
转发引用的概念背后是引用算法:
- && && = &&
- && & = &
- & && = &
- & & = &
让我们用转发引用来模拟编译器模板类型推导
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 推导出什么类型,您都会得到一个右值引用参数。