标准库函数 std::move
既然编译器只对右值引用才能调用转移构造函数和转移赋值函数,而所有的命名对象都只能是左值引用,如果已知一个命名对象不再被使用而想对他调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用,怎么做呢?标准库提供了函数std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
int a;
int &&r1 = a;// 编译失败
int &&r2 = std::move(a);//编译通过
完美转发 std::forward
完美转发适用于这样的场景:需要将一组参数原封不动的传递非另一个函数。
原封不动不仅仅是参数的值不变,在C++中,除了参数值之外,还有以下两组属性:左值/右值和const/non-const。完美转发就是在参数传递过程中,所有这些属性和参数值都不能改变,且不产生额外的开销,就好像转发者不存在一样。在泛型返回中,这样的需求非常普遍。
下面举例说明:
/*************************************************************************
> File Name: main.cpp
> Author: Xianghao Jia
> mail: xianghaojia@sina.com
> Created Time: Mon 09 Dec 2019 04:23:18 AM PST
************************************************************************/
#include <iostream>
using namespace std;
template <typename T> void process_value(T &val)
{
cout << "T&" << endl;
}
template <typename T> void process_value(const T &val)
{
cout << "const T &" << endl;
}
//函数forward_value是一个泛型函数,他将一个参数传递给另一个函数process_value
template <typename T> void forward_value(const T &val)
{
cout << "const T&" << endl;
process_value(val);
}
template <typename T> void forward_value(T &val)
{
cout << "T&" << endl;
process_value(val);
}
void test02()
{
int a = 0;
const int &b = 1;
forward_value(a);// T&
forward_value(b);// const T&
forward_value(2);// const T&
}
int main(int argc, char ** argv)
{
test02();
return 0;
}
对于一个参数就要重载两次,也就是重载函数的个数与参数个数成指数关系。这个函数的定义次数对于程序员来说是非常低效的。
那C++11是如何解决完美转发问题的呢?实际上,C++11是通过引入一条所谓“引用折叠”的新语言规则,并结合新的模板推导规则来完成完美转发。
typedef const int T;
typedef T & TR;
TR &v = 1; //在C++11中,一旦出现了这样的表达式,就会发生引用折叠,即将复杂的未知表达式折叠为已知的简单表达式
C++11中的引用折叠规则:
TR的类型定义 |
声明v的类型 |
v的实际类型 |
T & |
TR |
T & |
T & |
TR & |
T & |
T & |
TR && |
T & |
T && |
TR |
T && |
T && |
TR & |
T & |
T && |
TR && |
T && |
一旦定义中出现了左值引用,引用折叠总是优先将其折叠为左值引用
C++11中,std::forward可以保存参数的左值或右值特性
#include <iostream>
using namespace std;
template <typename T> void process_value(T & val)
{
cout << "T &" << endl;
}
template <typename T> void process_value(T && val)
{
cout << "T &&" << endl;
}
template <typename T> void process_value(const T & val)
{
cout << "const T &" << endl;
}
template <typename T> void process_value(const T && val)
{
cout << "const T &&" << endl;
}
//函数 forward_value 是一个泛型函数,它将一个参数传递给另一个函数 process_value
template <typename T> void forward_value(T && val) //参数为右值引用
{
process_value( std::forward<T>(val) );//C++11中,std::forward可以保存参数的左值或右值特性
}
int main()
{
int a = 0;
const int &b = 1;
forward_value(a); // T &
forward_value(b); // const T &
forward_value(2); // T &&
forward_value( std::move(b) ); // const T &&
return 0;
}
其他参考