【C++】C++11:可变模板参数、emplace

📅 2026/7/19 3:23:10
【C++】C++11:可变模板参数、emplace
C11可变模板参数、emplace1、可变模板参数的概念C11支持可变参数模板也就是说支持可变数量参数的函数模板和类模板例如templateclass...ArgsvoidFunc(Args...args){}templateclass...ArgsvoidFunc(Args...args){}templateclass...ArgsvoidFunc(Args...args){}上面的参数中Args是一个模板参数包args是一个函数形参参数包声明一个参数包Args… args这个参数包中可以包含0到任意个模板参数可变参数模板就是支持任意数量、任意类型参数参数包是用…来打包一堆参数我们无法直接获取参数包args中的每个参数语法不支持使用args[i]这样的方式获取可变参数只能通过展开参数包的方式来获取参数包中的每个参数2、获取参数包中参数的个数templateclass...ArgsvoidPrint(Args...args){coutsizeof...(args)endl;}intmain(){doublex2.2;Print();// 包里有0个参数Print(1);// 包里有1个参数Print(1,string(xxxxx));// 包里有2个参数Print(1.1,string(xxxxx),x);// 包里有3个参数return0;}输出结果0123可以通过sizeof… (args)来查看参数包中的参数个数3、递归函数方式展开参数包// 递归终止函数voidShowList(){coutendl;//所有参数打印完换行收尾}// 每次拆分出第一个参数T x剩下的打包成Args... argstemplateclassT,class...ArgsvoidShowList(T x,Args...args){// 先打印当前拆出来的第一个参数coutx ;// 将剩下没打印的args包继续传给自己递归拆解ShowList(args...);}// 接收任意个任意类型参数包转发给ShowList处理templateclass...ArgsvoidPrint(Args...args){ShowList(args...);}intmain(){doublex2.2;Print();// 包里有0个参数Print(1);// 包里有1个参数Print(1,string(xxxxx));// 包里有2个参数Print(1.1,string(xxxxx),x);// 包里有3个参数return0;}输出结果11 xxxxx1.1 xxxxx 2.2该方法是通过递归调用ShowList函数去获取参数包中的参数每递归一次就可以从参数包中取出一个参数存到形参val中。当参数包把最后一个参数传递给ShowList(T x, Args... args)后参数包中没有任何东西相当于无参调用ShowList()所以写了上面的递归终止函数这样就可以把参数包中的最后一个参数提取出来并结束递归在编译器底层5、emplace系列接口5.1 push_back的用法下面使用模拟实现的list配合string演示push_back和emplace_back的用法与差异intmain(){MyList::listMyList::stringlt;// 传左值跟push_back一样走拷贝构造MyList::strings1(111111111111);lt.emplace_back(s1);cout\nendl;// 右值跟push_back一样走移动构造lt.emplace_back(move(s1));cout\nendl;// 直接把构造string参数包往下传直接用string参数包构造string// 这里达到的效果是push_back做不到的lt.emplace_back(111111111111);// 构造lt.emplace_back(10,x);// 构造lt.push_back(111111111111);// 构造移动构造cout\nendl;// 链表中存日期类对象//lt.emplace_back(2025, 1, 1); // 构造//lt.push_back({ 2025, 1, 1 }); // 构造拷贝构造MyList::listpairMyList::string,intlt1;// 跟push_back一样// 构造pair 拷贝/移动构造pair到list的节点中data上pairMyList::string,intkv(苹果,1);lt1.emplace_back(kv);cout\nendl;// 跟push_back一样lt1.emplace_back(move(kv));cout\nendl;////////////////////////////////////////////////////////////////////// 直接把构造pair参数包往下传直接用pair参数包构造pair// 这里达到的效果是push_back做不到的lt1.emplace_back(苹果,1);// lt1.emplace_back({ 苹果, 1 }); 不支持,形参是模板无法推导形参类型lt1.push_back({苹果,1});// 隐式类型转换传参cout\nendl;return0;}输出结果由上面的代码可以发现如果使用push_back传递构造pair的参数那么会产生构造和移动构造如果使用emplace_back传递构造pair的参数那么只会产生一次构造可以提高效率5.2 emplace_back使用方法templateclass...Argsvoidemplace_back(Args...args);emplace_back和push_back最大的区别是push_back的参数类型是固定的而emplace_back采用的是可变模板参数,push_back的三种使用方式同样适用于emplace_backlist中的应用templateclass...Argsvoidemplace_back(Args...args){emplace(end(),forwardArgs(args)...);}// 优化后的inserttemplateclass...Argsvoidemplace(iterator pos,Args...args){Node*curpos._node;Node*prevcur-_prev;Node*newnodenewNode(forwardArgs(args)...);// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;_size;}// 改造构造函数templateclass...Argslist_node(Args...args):_next(nullptr),_prev(nullptr),_data(forwardArgs(args)...){}普通insert必须先造好完整pair对象再插入bit::listpairstring,intlt;lt.insert(lt.begin(),pairstring,int(苹果,1));emplace函数lt.emplace(it,苹果,1);emplace_back新增的用法lt.emplace_back(10,x);使用函数templateclass...Argsvoidemplace_back(Args...args){emplace(end(),forwardArgs(args)...);}emplace_back 直接传构造参数原地构造无临时push_back只能传完整对象必须先生成临时stringlt.push_back(string(10,x));6、list改良后代码#pragmaonce#pragmaonce#includeassert.hnamespaceMyList{templateclassTstructlist_node{list_node*_next;list_node*_prev;T _data;list_node(constTx):_next(nullptr),_prev(nullptr),_data(x){}list_node(TxT()):_next(nullptr),_prev(nullptr),_data(move(x)){}templateclass...Argslist_node(Args...args):_next(nullptr),_prev(nullptr),_data(forwardArgs(args)...){}};// typedef list_iteratorT, T, T* iterator;// typedef list_iteratorT, const T, const T* const_iterator;templateclassT,classRef,classPtrstructlist_iterator{typedeflist_nodeTNode;typedeflist_iteratorT,Ref,PtrSelf;Node*_node;list_iterator(Node*node):_node(node){}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)const{return_node!s._node;}booloperator(constSelfs)const{return_nodes._node;}};templateclassTclasslist{typedeflist_nodeTNode;public:typedeflist_iteratorT,T,T*iterator;//typedef list_const_iteratorT const_iterator;typedeflist_iteratorT,constT,constT*const_iterator;iteratorbegin(){returniterator(_head-_next);}iteratorend(){returniterator(_head);}const_iteratorbegin()const{returnconst_iterator(_head-_next);}const_iteratorend()const{returnconst_iterator(_head);}voidempty_init(){_headnewNode;_head-_next_head;_head-_prev_head;_size0;}list(){empty_init();}list(initializer_listTil){empty_init();for(autoe:il){push_back(e);}}// lt2(lt1)//list(const listT lt)list(listTlt){empty_init();for(autoe:lt){push_back(e);}}voidswap(listTlt){std::swap(_head,lt._head);std::swap(_size,lt._size);}// lt1 lt3listToperator(listTlt){swap(lt);return*this;}~list(){clear();delete_head;_headnullptr;}voidclear(){autoitbegin();while(it!end()){iterase(it);}}size_tsize(){return_size;}voidpush_back(constTx){insert(end(),x);}// 不是万能引用// T是通过实参传递推导的吗不是T是list实例化的voidpush_back(Tx){//insert(end(), move(x));insert(end(),(T)x);}// 万能引用//templateclass X//void push_back(X x)//{// // 保持他的属性往下传递左值引用就是保持左值属性右值引用就保持右值属性// insert(end(), forwardX(x));//}//templateclass X//void insert(iterator pos, X x)//{// Node* cur pos._node;// Node* prev cur-_prev;// Node* newnode new Node(forwardX(x));// // prev newnode cur// prev-_next newnode;// newnode-_prev prev;// newnode-_next cur;// cur-_prev newnode;// _size;//}templateclass...Argsvoidemplace_back(Args...args){emplace(end(),forwardArgs(args)...);}templateclass...Argsvoidemplace(iterator pos,Args...args){Node*curpos._node;Node*prevcur-_prev;Node*newnodenewNode(forwardArgs(args)...);// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;_size;}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*newnodenewNode(x);// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;_size;}voidinsert(iterator pos,Tx){Node*curpos._node;Node*prevcur-_prev;Node*newnodenewNode(move(x));// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;_size;}iteratorerase(iterator pos){assert(pos!end());Node*curpos._node;Node*prevcur-_prev;Node*nextcur-_next;prev-_nextnext;next-_prevprev;deletecur;--_size;//return iterator(next);returnnext;}private:Node*_head;size_t _size;};