文章目录1. 模板中的—万能引用2. 完美转发及其应用场景3. 用到的代码3.1 string.h3.2 list.h3.3 test.cpp1. 模板中的—万能引用首先我们来看这样一段代码这里有4个函数我们很容易能看出来它们是一个重载的关系然后我们给这样一个函数模板大家看这个函数模板的参数T t这里有两个所以它是右值引用吗不是的模板中的不代表右值引用而是万能引用其既能接收左值又能接收右值。我们实例化这个函数模板的时候可以传左值也可以传右值。我们传的是左值那参数t就是左值引用我们传的是右值参数t就是右值引用。所以有些地方也把它叫做引用折叠就是我们传左值的时候它好像就把折叠了一下一样。C中不能直接定义引用的引用如int r i;这样写会直接报错但通过模板或 typedef 中的类型操作可能构成引用的引用。比如这时C11给出了⼀个引用折叠的规则右值引用的右值引用折叠成右值引用所有其他组合均折叠成左值引用。若有const则const属性会被保留这时再看上面r1到r4的类型你就懂了。比如上面的模板参数是看作右值引用那你传右值引用就是右值引用传左值引用就是左值引用。如果模板参数为左值引用那你无论传什么最终都是左值引用因为只有右值引用的右值引用才会折叠为右值引用。看一个模板中的例子所以但是大家看到我们这里接收t之后又往下传了一层那大家就要思考一下在PerfectForward函数内部t又往下传给了Fun那传给Fun的话t会匹配什么呢那我们来运行一下程序看看结果欸怎么回事啊为什么全部匹配的都是左值引用啊那这里为什么会这样呢还记不记得上一篇文章里面又给大家提过一个东西就是右值不能取地址但是给右值取别名后会导致右值被存储到特定位置且可以取到该位置的地址。例如不能取字面量10的地址但是rr1引用后可以对rr1取地址也可以修改rr1。那可以取地址、可以赋值的话他不就变成左值了嘛。所以一个右值被右值引用后属性会变成左值那想一想其实这样设计也是合理的比如这个场景转移资源也可以认为是修改它了而临时变量或匿名对象这样将亡值是不能修改的。那再回过头来看我们上面的问题大家就应该明白了即使我们传过去的是右值那它被右值引用之后也会变成左值所以里面再传给Fun都匹配的是左值。所以说模板的万能引用只是提供了能够同时接收左值和右值的能力作用就是限制了接收的类型但在后续使用中都退化成了左值。但是有些场景下我们希望能够在传递过程中保持它的左值或者右值的属性那要如何做到呢就需要用我们下面学习的完美转发2. 完美转发及其应用场景首先我们来看一个对应的场景我们之前模拟实现过list搞一份过来有些用不到的东西就给它删了。配合我们自己搞的那个string把string里面我们添进去的移动拷贝和移动构造我也先注释掉我写这样一段代码那我们之前的实现并没有移动语义所以全是深拷贝不论左值还是右值。那我们把string的移动构造和移动拷贝放出来然后我给list的push_back增加右值引用的版本但是我们的push_back复用了insert所以insert也增加右值引用版本再来运行欸怎么还不行list的push_back还是都是深拷贝啊问题出在哪里呢是不是就是我们上面提到的问题啊右值被右值引用后就变成了左值。在第一次传递给push_back 的参数右值的话就调用右值引用版本的push_back 但是push_back里面调用insert第二次传递就变成左值了所以最终不论是右值还是左值的push_back最终调的insert都是左值版本的所以都是深拷贝那如何解决这个问题呢如何在在传递过程中保持它的左值或者右值的属性呢这就要用到完美转发std::forward 完美转发在传参的过程中保留对象原生类型属性也是库里面提供的一个函数模板那我们直接调用forward来保持参数的原生属性那我们再来运行哎呀怎么还不行因为下面其实还有一层传递insert里面创建新结点的时候要调用node的构造函数所以这里也要加forward但是node的构造函数我们只有左值引用的版本所以我们要再增加一个右值引用的版本并且这里_data的初始化我们也要用forward保持x它的属性因为我们现在存string他会调string的构造这里保持它是右值才会调到右值引用版本的移动拷贝那这下就可以了右值的push_back就是移动拷贝了那有了完美转发我们最开始那个场景都匹配的是右值引用的版本怎么办加个完美转发就可以了3. 用到的代码3.1 string.h#pragmaoncenamespacebit{classstring{public:typedefchar*iterator;iteratorbegin(){return_str;}iteratorend(){return_str_size;}string(constchar*str):_size(strlen(str)),_capacity(_size){//cout string(char* str) endl;_strnewchar[_capacity1];strcpy(_str,str);}// s1.swap(s2)voidswap(strings){std::swap(_str,s._str);std::swap(_size,s._size);std::swap(_capacity,s._capacity);}// 拷贝构造string(conststrings):_str(nullptr){coutstring(const string s) -- 深拷贝endl;stringtmp(s._str);swap(tmp);}// 移动构造string(strings):_str(nullptr){coutstring(string s) -- 移动拷贝endl;swap(s);}// 赋值重载stringoperator(conststrings){coutstring operator(string s) -- 深拷贝endl;stringtmp(s);swap(tmp);return*this;}// 移动赋值stringoperator(strings){coutstring operator(string s) -- 移动赋值endl;swap(s);return*this;}~string(){delete[]_str;_strnullptr;}charoperator[](size_t pos){assert(pos_size);return_str[pos];}voidreserve(size_t n){if(n_capacity){char*tmpnewchar[n1];strcpy(tmp,_str);delete[]_str;_strtmp;_capacityn;}}voidpush_back(charch){if(_size_capacity){size_t newcapacity_capacity0?4:_capacity*2;reserve(newcapacity);}_str[_size]ch;_size;_str[_size]\0;}//string operator(char ch)stringoperator(charch){push_back(ch);return*this;}stringoperator(charch){stringtmp(*this);tmpch;returntmp;}constchar*c_str()const{return_str;}private:char*_str;size_t _size;size_t _capacity;// 不包含最后做标识的\0};stringto_string(intvalue){boolflagtrue;if(value0){flagfalse;value0-value;}string str;while(value0){intxvalue%10;value/10;str(0x);}if(flagfalse){str-;}std::reverse(str.begin(),str.end());returnstr;}}3.2 list.h#pragmaonce#includeassert.hnamespaceyin{templateclassTstructlist_node{list_nodeT*_next;list_nodeT*_prev;T _data;list_node(constTxT()):_next(nullptr),_prev(nullptr),_data(x){}list_node(TxT()):_next(nullptr),_prev(nullptr),_data(forwardT(x)){}};// 1、迭代器要么就是原生指针// 2、迭代器要么就是自定义类型对原生指针的封装模拟指针的行为templateclassT,classRef,classPtrstruct__list_iterator{typedeflist_nodeTnode;typedef__list_iteratorT,Ref,Ptrself;node*_node;__list_iterator(node*n):_node(n){}Refoperator*(){return_node-_data;}Ptroperator-(){return_node-_data;}selfoperator(){_node_node-_next;return*this;}selfoperator(int){selftmp(*this);_node_node-_next;returntmp;}selfoperator--(){_node_node-_prev;return*this;}selfoperator--(int){selftmp(*this);_node_node-_prev;returntmp;}booloperator!(constselfs){return_node!s._node;}booloperator(constselfs){return_nodes._node;}};templateclassTclasslist{typedeflist_nodeTnode;public:typedef__list_iteratorT,T,T*iterator;typedef__list_iteratorT,constT,constT*const_iterator;iteratorbegin(){//iterator it(_head-_next);//return it;returniterator(_head-_next);}const_iteratorbegin()const{returnconst_iterator(_head-_next);}iteratorend(){returniterator(_head);}const_iteratorend()const{//iterator it(_head-_next);//return it;returnconst_iterator(_head);}voidempty_init(){_headnewnode(T());_head-_next_head;_head-_prev_head;}list(){empty_init();}templateclassIteratorlist(Iterator first,Iterator last){empty_init();while(first!last){push_back(*first);first;}}voidswap(listTtmp){std::swap(_head,tmp._head);}list(constlistTlt){empty_init();listTtmp(lt.begin(),lt.end());swap(tmp);}// lt1 lt3listToperator(listTlt){swap(lt);return*this;}~list(){clear();delete_head;_headnullptr;}voidclear(){iterator itbegin();while(it!end()){//it erase(it);erase(it);}}voidpush_back(constTx){insert(end(),x);}voidpush_back(Tx){insert(end(),forwardT(x));}voidpush_front(constTx){insert(begin(),x);}voidpop_back(){erase(--end());}voidpop_front(){erase(begin());}voidinsert(iterator pos,constTx){node*curpos._node;node*prevcur-_prev;node*new_nodenewnode(x);prev-_nextnew_node;new_node-_prevprev;new_node-_nextcur;cur-_prevnew_node;}voidinsert(iterator pos,Tx){node*curpos._node;node*prevcur-_prev;node*new_nodenewnode(forwardT(x));prev-_nextnew_node;new_node-_prevprev;new_node-_nextcur;cur-_prevnew_node;}iteratorerase(iterator pos){assert(pos!end());node*prevpos._node-_prev;node*nextpos._node-_next;prev-_nextnext;next-_prevprev;deletepos._node;returniterator(next);}private:node*_head;};}3.3 test.cppvoidFun(intx){cout左值引用endl;}voidFun(constintx){coutconst 左值引用endl;}voidFun(intx){cout右值引用endl;}voidFun(constintx){coutconst 右值引用endl;}templatetypenameTvoidPerfectForward(Tt){Fun(forwardT(t));}intmain(){PerfectForward(10);// 右值inta;PerfectForward(a);// 左值PerfectForward(move(a));// 右值constintb8;PerfectForward(b);// const 左值PerfectForward(move(b));// const 右值return0;}//#include list.h////int main()//{// yin::listbit::string lt;//// bit::string s1(hello world);// lt.push_back(s1);//// lt.push_back(bit::string(hello world));// lt.push_back(hello world);//// return 0;//}