您的位置:首页 > 编程语言 > C语言/C++

杂货边角(25):完美转发

2018-02-28 18:40 176 查看
完美转发是C++11借助右值引用这个引入的特性而顺带完成的一个很美的特性,涉及到两个重要的概念:引用折叠和模板参数推导。

#include <iostream>
#include <type_traits>
using namespace std;

void RunCode(int && m ) { cout << "rvalue ref" << endl; }
void RunCode(int & m)   { cout << "lvalue ref" << endl; }
void RunCode(const int && m) { cout << "const rvalue ref" << endl; }
void RunCode(const int & m)  { cout << "const lvalue ref" << endl; }

template <typename T>
void PerfectForward(T && t) { RunCode(forward<T>(t)); } //C++标准规定,具名的右值引用当作左值,故而这里必须得有forward<T>强制类型转换在,
//不然直接写成RunCode(t)那么其中的t将被看做左值

template <typename T, typename U>
void PerfectForward(T && t, U& Func) {
cout << t << "\tforward..." << endl;
Func(forward<T>(t));
}

void RunPart(double&& m) { cout << "get inside " << __func__ << endl; }
void RunHome(double&& h) { cout << "get inside " << __func__ << endl; }
void RunComp(double&& c) { cout << "get inside " << __func__ << endl; }

// 1. the return type (bool) is only valid if T is an integral type:
template <class T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
is_odd (T i) {return bool(i%2);}

// 2. the second template argument is only valid if T is an integral type:
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}

int main()
{
int a;
int b;
const int c = 1;
const int d = 0;

PerfectForward(a);
PerfectForward(move(b));
PerfectForward(c);
PerfectForward(move(d));

PerfectForward(1.5, RunComp); //不借助typeList‘< >’进行特化,而是直接传入参数进行特化
PerfectForward(8, RunPart);
PerfectForward(1.5, RunHome);

int i = 1;
double j = 1.0;

cout << std::boolalpha; //声明ostream中的所有bool量用true/false表示而非1/0,类比std::hex
cout << "i is odd: " << is_odd(i) << endl;
cout << "i is even: " << is_even(i) << endl;
//cout << "j is odd: " << is_odd(j) << endl; //找不到匹配的函数
//cout << "j is even: " << is_even(j) << endl; //因为模板is_even的第二个参数无效,故而无法正常实例化,从而出现找不到匹配的函数for call to 'is_even(double&)`
}

/**************************************************
**完美转发是一个很棒的机制。对于完美转发而言,右值引用并非“天生神力”,只是C++11引入了右值
**概念,因此为其新定了引用折叠的规则,以满足完美转发的需求
**************************************************/




这里面最值得说的以及最容易混淆的莫过于引用折叠,这篇文章有很好的解释。举个简单的常见来说明:

//完美转发函数
template <typename T>
void PerfectForward(T && t) {
T temp;
//to-do ...
}

...
int a = 1;      PerfectForward(a);
int& la = a;    PerfectForward(la);
int&& ra = 10;  PerfectForward(ra);
//依次用左值,左值引用,右值引用调用转发函数,则T&& t实际的类型,以及模板参数T对应的类型规则如下:


模板形参t被声明的类型调用时实际传入的实参类型调用后形参t的实际类型调用后T的实际类型
T&A& or AA&A
T&A&&A&A
T&&A& or AA&A&
T&&A&&A&&A
其中值得注意的是,当采用完美转发特色&&解析模板形参时,调用时实参为左值时和为左值引用的情况一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++11 完美转发