咋样做班级主页网站,用ps怎么做短视频网站,平安秦皇岛建设,深圳做二维码网站建设C元编程完全指南#xff1a;从入门到精通
目录
什么是元编程模板基础模板元编程核心技术类型萃取与类型操作SFINAE与enable_ifconstexpr与编译期计算变参模板模板特化与偏特化类型列表与元容器实战案例C20概念与约束性能优化与最佳实践 什么是元编程
元编程#xff08;Met…C元编程完全指南从入门到精通目录什么是元编程模板基础模板元编程核心技术类型萃取与类型操作SFINAE与enable_ifconstexpr与编译期计算变参模板模板特化与偏特化类型列表与元容器实战案例C20概念与约束性能优化与最佳实践什么是元编程元编程Metaprogramming是指编写能够生成或操作程序的程序。在C中元编程主要通过模板在编译期执行计算和类型操作。元编程的优势零运行时开销所有计算在编译期完成类型安全编译期类型检查代码生成自动生成重复代码性能优化编译器可以进行更深度的优化元编程 vs 运行时编程// 运行时计算阶乘intfactorial_runtime(intn){returnn1?1:n*factorial_runtime(n-1);}// 编译期计算阶乘模板元编程templateintNstructFactorial{staticconstexprintvalueN*FactorialN-1::value;};templatestructFactorial0{staticconstexprintvalue1;};// 使用intmain(){intrtfactorial_runtime(5);// 运行时计算constexprintctFactorial5::value;// 编译期计算结果直接嵌入代码}模板基础函数模板// 基础函数模板templatetypenameTTmax(T a,T b){returnab?a:b;}// 多个模板参数templatetypenameT,typenameUautoadd(T a,U b)-decltype(ab){returnab;}// 非类型模板参数templatetypenameT,size_t Nsize_tarraySize(T()[N]){returnN;}类模板// 基础类模板templatetypenameTclassContainer{T data;public:Container(T val):data(val){}Tget()const{returndata;}};// 多个模板参数templatetypenameKey,typenameValueclassPair{Key key;Value value;public:Pair(Key k,Value v):key(k),value(v){}};// 默认模板参数templatetypenameT,typenameAllocatorstd::allocatorTclassMyVector{// ...};模板元编程核心技术1. 递归模板实例化模板元编程的核心是通过递归实例化来实现循环// 编译期计算斐波那契数列templateintNstructFibonacci{staticconstexprintvalueFibonacciN-1::valueFibonacciN-2::value;};templatestructFibonacci0{staticconstexprintvalue0;};templatestructFibonacci1{staticconstexprintvalue1;};// 使用constexprintfib10Fibonacci10::value;// 552. 类型作为值在元编程中类型本身就是值// 类型包装器templatetypenameTstructTypeWrapper{usingtypeT;};// 条件类型选择templateboolCondition,typenameTrueType,typenameFalseTypestructConditional{usingtypeTrueType;};templatetypenameTrueType,typenameFalseTypestructConditionalfalse,TrueType,FalseType{usingtypeFalseType;};// 使用usingResultConditionaltrue,int,double::type;// int3. 编译期分支// 编译期if-elsetemplateboolConditionstructCompileTimeIf{templatetypenameTrueFunc,typenameFalseFuncstaticautoexecute(TrueFunc tf,FalseFunc ff){returntf();}};templatestructCompileTimeIffalse{templatetypenameTrueFunc,typenameFalseFuncstaticautoexecute(TrueFunc tf,FalseFunc ff){returnff();}};类型萃取与类型操作标准库类型萃取#includetype_traits// 判断类型属性static_assert(std::is_integralint::value,int is integral);static_assert(std::is_floating_pointdouble::value,double is floating point);static_assert(std::is_pointerint*::value,int* is pointer);static_assert(std::is_constconstint::value,const int is const);// 类型转换usingT1std::remove_constconstint::type;// intusingT2std::remove_referenceint::type;// intusingT3std::add_pointerint::type;// int*usingT4std::decayint[10]::type;// int*自定义类型萃取// 判断是否是指针类型templatetypenameTstructIsPointer{staticconstexprboolvaluefalse;};templatetypenameTstructIsPointerT*{staticconstexprboolvaluetrue;};// 获取指针指向的类型templatetypenameTstructRemovePointer{usingtypeT;};templatetypenameTstructRemovePointerT*{usingtypeT;};// 判断是否有特定成员templatetypenameTclassHasToString{templatetypenameUstaticautotest(int)-decltype(std::declvalU().toString(),std::true_type{});templatetypenamestaticstd::false_typetest(...);public:staticconstexprboolvaluedecltype(testT(0))::value;};// 使用classMyClass{public:std::stringtoString(){returnMyClass;}};static_assert(HasToStringMyClass::value,MyClass has toString);static_assert(!HasToStringint::value,int doesnt have toString);SFINAE与enable_ifSFINAESubstitution Failure Is Not An Error是C模板元编程的核心机制。SFINAE基础// 当T有size()方法时启用此版本templatetypenameTautogetSize(constTcontainer)-decltype(container.size()){returncontainer.size();}// 当T是数组时启用此版本templatetypenameT,size_t Nsize_tgetSize(constT()[N]){returnN;}std::enable_if#includetype_traits// 只对整数类型启用templatetypenameTtypenamestd::enable_ifstd::is_integralT::value,T::typemultiply(T a,T b){returna*b;}// 只对浮点类型启用templatetypenameTtypenamestd::enable_ifstd::is_floating_pointT::value,T::typemultiply(T a,T b){returna*b*1.0;}// C14简化写法templatetypenameTstd::enable_if_tstd::is_integralT::value,Tadd(T a,T b){returnab;}// 作为模板参数使用templatetypenameT,typenamestd::enable_if_tstd::is_arithmeticT::valueclassCalculator{T value;public:Calculator(T v):value(v){}TgetValue()const{returnvalue;}};高级SFINAE技巧// void_t技巧C17templatetypename...usingvoid_tvoid;// 检测成员类型templatetypename,typenamevoidstructHasValueType:std::false_type{};templatetypenameTstructHasValueTypeT,void_ttypenameT::value_type:std::true_type{};// 检测成员函数templatetypename,typenamevoidstructHasPushBack:std::false_type{};templatetypenameTstructHasPushBackT,void_tdecltype(std::declvalT().push_back(std::declvaltypenameT::value_type())):std::true_type{};// 使用static_assert(HasValueTypestd::vectorint::value,vector has value_type);static_assert(HasPushBackstd::vectorint::value,vector has push_back);constexpr与编译期计算constexpr函数// C11 constexpr单一return语句constexprintsquare(intx){returnx*x;}// C14 constexpr允许多条语句constexprintfactorial(intn){intresult1;for(inti2;in;i){result*i;}returnresult;}// 编译期计算constexprintvalfactorial(5);// 120编译期计算// 运行时计算intn5;intval2factorial(n);// 运行时计算constexpr类classPoint{intx_,y_;public:constexprPoint(intx,inty):x_(x),y_(y){}constexprintx()const{returnx_;}constexprinty()const{returny_;}constexprPointoperator(constPointother)const{returnPoint(x_other.x_,y_other.y_);}constexprintdistanceSquared()const{returnx_*x_y_*y_;}};// 编译期计算constexprPointp1(3,4);constexprPointp2(1,2);constexprPoint p3p1p2;constexprintdistp3.distanceSquared();// 52constexpr vs 模板元编程// 模板元编程方式templateintNstructPower2{staticconstexprintvalue2*Power2N-1::value;};templatestructPower20{staticconstexprintvalue1;};// constexpr方式更简洁constexprintpower2(intn){returnn0?1:2*power2(n-1);}// 使用constexprintv1Power210::value;// 1024constexprintv2power2(10);// 1024变参模板变参模板Variadic Templates允许模板接受任意数量的参数。基础语法// 递归展开templatetypenameTvoidprint(constTvalue){std::coutvaluestd::endl;}templatetypenameT,typename...Argsvoidprint(constTfirst,constArgs...rest){std::coutfirst, ;print(rest...);// 递归调用}// 使用print(1,2.5,hello,c);// 1, 2.5, hello, c参数包展开// sizeof...运算符templatetypename...Argssize_tcount(Args...args){returnsizeof...(args);}// 折叠表达式C17templatetypename...Argsautosum(Args...args){return(args...);// 一元右折叠}templatetypename...Argsautosum_with_init(Args...args){return(0...args);// 二元左折叠}templatetypename...ArgsvoidprintAll(constArgs...args){(std::cout...args)std::endl;// 折叠表达式}// 使用autos1sum(1,2,3,4,5);// 15autos2sum_with_init(1,2,3);// 6printAll(1, ,2, ,3);// 1 2 3变参模板高级应用// 完美转发templatetypename...Argsautomake_unique_wrapper(Args...args){returnstd::make_uniqueMyClass(std::forwardArgs(args)...);}// 索引序列templatesize_t...IndicesstructIndexSequence{};templatesize_t N,size_t...IndicesstructMakeIndexSequence:MakeIndexSequenceN-1,N-1,Indices...{};templatesize_t...IndicesstructMakeIndexSequence0,Indices...{usingtypeIndexSequenceIndices...;};// 应用到元组templatetypenameTuple,size_t...IndicesvoidprintTupleImpl(constTuplet,IndexSequenceIndices...){((std::coutstd::getIndices(t) ),...);}templatetypename...ArgsvoidprintTuple(conststd::tupleArgs...t){printTupleImpl(t,typenameMakeIndexSequencesizeof...(Args)::type{});}// 使用autotstd::make_tuple(1,2.5,hello);printTuple(t);// 1 2.5 hello模板特化与偏特化全特化// 主模板templatetypenameTclassStorage{T data;public:voidset(T value){datavalue;}Tget()const{returndata;}};// 全特化bool类型templateclassStoragebool{unsignedchardata;public:voidset(boolvalue){datavalue?1:0;}boolget()const{returndata!0;}};偏特化// 主模板templatetypenameT,typenameUclassPair{T first;U second;public:Pair(T f,U s):first(f),second(s){}};// 偏特化两个类型相同templatetypenameTclassPairT,T{T data[2];public:Pair(T f,T s){data[0]f;data[1]s;}};// 偏特化指针类型templatetypenameT,typenameUclassPairT*,U*{T*first;U*second;public:Pair(T*f,U*s):first(f),second(s){}~Pair(){deletefirst;deletesecond;}};函数模板特化// 主模板templatetypenameTvoidswap(Ta,Tb){T tempa;ab;btemp;}// 特化数组templatetypenameT,size_t Nvoidswap(T(a)[N],T(b)[N]){for(size_t i0;iN;i){swap(a[i],b[i]);}}特化的应用类型选择// 根据大小选择类型templatesize_t SizestructSelectIntType;templatestructSelectIntType1{usingtypeint8_t;};templatestructSelectIntType2{usingtypeint16_t;};templatestructSelectIntType4{usingtypeint32_t;};templatestructSelectIntType8{usingtypeint64_t;};// 使用usingSmallIntSelectIntType2::type;// int16_t类型列表与元容器类型列表// 类型列表定义templatetypename...TypesstructTypeList{};// 获取长度templatetypenameListstructLength;templatetypename...TypesstructLengthTypeListTypes...{staticconstexprsize_t valuesizeof...(Types);};// 获取第N个类型templatesize_t N,typenameListstructTypeAt;templatesize_t N,typenameHead,typename...TailstructTypeAtN,TypeListHead,Tail...{usingtypetypenameTypeAtN-1,TypeListTail...::type;};templatetypenameHead,typename...TailstructTypeAt0,TypeListHead,Tail...{usingtypeHead;};// 添加类型到前面templatetypenameT,typenameListstructPushFront;templatetypenameT,typename...TypesstructPushFrontT,TypeListTypes...{usingtypeTypeListT,Types...;};// 添加类型到后面templatetypenameT,typenameListstructPushBack;templatetypenameT,typename...TypesstructPushBackT,TypeListTypes...{usingtypeTypeListTypes...,T;};// 使用usingMyListTypeListint,double,char;static_assert(LengthMyList::value3,Length is 3);usingSecondTypeTypeAt1,MyList::type;// doubleusingNewListPushFrontfloat,MyList::type;// TypeListfloat, int, double, char类型列表算法// 查找类型templatetypenameT,typenameListstructIndexOf;templatetypenameTstructIndexOfT,TypeList{staticconstexprintvalue-1;};templatetypenameT,typename...TailstructIndexOfT,TypeListT,Tail...{staticconstexprintvalue0;};templatetypenameT,typenameHead,typename...TailstructIndexOfT,TypeListHead,Tail...{private:staticconstexprinttempIndexOfT,TypeListTail...::value;public:staticconstexprintvaluetemp-1?-1:1temp;};// 类型转换templatetemplatetypenameclassTransform,typenameListstructTransformList;templatetemplatetypenameclassTransform,typename...TypesstructTransformListTransform,TypeListTypes...{usingtypeTypeListtypenameTransformTypes::type...;};// 过滤类型templatetemplatetypenameclassPredicate,typenameListstructFilterList;templatetemplatetypenameclassPredicatestructFilterListPredicate,TypeList{usingtypeTypeList;};templatetemplatetypenameclassPredicate,typenameHead,typename...TailstructFilterListPredicate,TypeListHead,Tail...{private:usingTailResulttypenameFilterListPredicate,TypeListTail...::type;public:usingtypetypenamestd::conditionalPredicateHead::value,typenamePushFrontHead,TailResult::type,TailResult::type;};// 使用usingMyListTypeListint,double,int*,char,float*;static_assert(IndexOfdouble,MyList::value1,double is at index 1);// 移除指针usingNonPointersFilterListstd::is_pointer,MyList::type;实战案例案例1编译期字符串哈希// 编译期字符串哈希用于switch-case字符串constexpruint64_thash_string(constchar*str,uint64_thash14695981039346656037ULL){return*str0?hash:hash_string(str1,(hash^*str)*1099511628211ULL);}// 使用voidprocessCommand(constchar*cmd){switch(hash_string(cmd)){casehash_string(start):std::coutStarting...std::endl;break;casehash_string(stop):std::coutStopping...std::endl;break;casehash_string(restart):std::coutRestarting...std::endl;break;default:std::coutUnknown commandstd::endl;}}案例2类型安全的单位系统// 单位系统templateintM,intKg,intS// 米、千克、秒的指数structUnit{staticconstexprintmeterM;staticconstexprintkilogramKg;staticconstexprintsecondS;};templatetypenameUclassQuantity{doublevalue_;public:explicitconstexprQuantity(doublev):value_(v){}constexprdoublevalue()const{returnvalue_;}// 加法相同单位constexprQuantityoperator(constQuantityother)const{returnQuantity(value_other.value_);}// 乘法单位相乘templatetypenameU2constexprautooperator*(constQuantityU2other)const{usingResultUnitUnitU::meterU2::meter,U::kilogramU2::kilogram,U::secondU2::second;returnQuantityResultUnit(value_*other.value());}// 除法单位相除templatetypenameU2constexprautooperator/(constQuantityU2other)const{usingResultUnitUnitU::meter-U2::meter,U::kilogram-U2::kilogram,U::second-U2::second;returnQuantityResultUnit(value_/other.value());}};// 定义基本单位usingMeterUnit1,0,0;usingSecondUnit0,0,1;usingKilogramUnit0,1,0;usingMeterPerSecondUnit1,0,-1;usingMeterPerSecondSquaredUnit1,0,-2;// 使用constexprQuantityMeterdistance(100.0);constexprQuantitySecondtime(10.0);constexprautospeeddistance/time;// QuantityMeterPerSecond// auto invalid distance time; // 编译错误不能将距离和时间相加案例3编译期正则表达式匹配器// 简化的编译期正则表达式templatechar...CharsstructPattern{};// 匹配器templatetypenamePstructMatcher;// 匹配单个字符templatecharCstructMatcherPatternC{staticconstexprboolmatch(constchar*str){return*strC*(str1)\0;}};// 匹配序列templatecharC,char...ReststructMatcherPatternC,Rest...{staticconstexprboolmatch(constchar*str){return*strCMatcherPatternRest...::match(str1);}};// 使用字面量运算符templatetypenameT,T...CharsconstexprPatternChars...operator_pattern(){return{};}// 使用constexprautopatternhello_pattern;static_assert(Matcherdecltype(pattern)::match(hello),Matches!);案例4反射系统// 简单的反射系统#defineREFLECT_MEMBER(Type,Member)\{#Member,offsetof(Type,Member),typeid(decltype(Type::Member))}templatetypenameTstructMemberInfo{constchar*name;size_t offset;conststd::type_infotype;};templatetypenameT,size_t NstructClassInfo{constchar*className;MemberInfoTmembers[N];templatetypenameFuncvoidforEachMember(Tobj,Func func)const{for(size_t i0;iN;i){func(members[i],obj);}}};// 使用示例structPerson{std::string name;intage;doubleheight;};constexprClassInfoPerson,3personInfo{Person,{REFLECT_MEMBER(Person,name),REFLECT_MEMBER(Person,age),REFLECT_MEMBER(Person,height)}};// 序列化示例voidserialize(constPersonp){personInfo.forEachMember(const_castPerson(p),[](constautomember,autoobj){std::coutmember.name: ;// 根据类型输出值if(member.typetypeid(std::string)){autovalue*reinterpret_caststd::string*(reinterpret_castchar*(obj)member.offset);std::coutvalue;}elseif(member.typetypeid(int)){autovalue*reinterpret_castint*(reinterpret_castchar*(obj)member.offset);std::coutvalue;}elseif(member.typetypeid(double)){autovalue*reinterpret_castdouble*(reinterpret_castchar*(obj)member.offset);std::coutvalue;}std::coutstd::endl;});}案例5表达式模板// 表达式模板用于延迟计算和优化templatetypenameEclassVecExpression{public:doubleoperator[](size_t i)const{returnstatic_castconstE(*this)[i];}size_tsize()const{returnstatic_castconstE(*this).size();}};classVec:publicVecExpressionVec{std::vectordoubledata_;public:Vec(size_t n):data_(n){}Vec(std::initializer_listdoubleinit):data_(init){}doubleoperator[](size_t i)const{returndata_[i];}doubleoperator[](size_t i){returndata_[i];}size_tsize()const{returndata_.size();}// 从表达式赋值templatetypenameEVecoperator(constVecExpressionEexpr){constEestatic_castconstE(expr);for(size_t i0;isize();i){data_[i]e[i];}return*this;}};// 加法表达式templatetypenameE1,typenameE2classVecSum:publicVecExpressionVecSumE1,E2{constE1u_;constE2v_;public:VecSum(constE1u,constE2v):u_(u),v_(v){}doubleoperator[](size_t i)const{returnu_[i]v_[i];}size_tsize()const{returnu_.size();}};// 乘法表达式templatetypenameEclassVecScale:publicVecExpressionVecScaleE{constEv_;doublescalar_;public:VecScale(constEv,doublescalar):v_(v),scalar_(scalar){}doubleoperator[](size_t i)const{returnv_[i]*scalar_;}size_tsize()const{returnv_.size();}};// 运算符重载templatetypenameE1,typenameE2VecSumE1,E2operator(constVecExpressionE1u,constVecExpressionE2v){returnVecSumE1,E2(static_castconstE1(u),static_castconstE2(v));}templatetypenameEVecScaleEoperator*(constVecExpressionEv,doublescalar){returnVecScaleE(static_castconstE(v),scalar);}// 使用Vec a{1,2,3};Vec b{4,5,6};Vec c{7,8,9};Vecresult(3);// 这个表达式不会创建临时对象而是在赋值时一次性计算resultab*2.0c;// 等价于result[i] a[i] b[i] * 2.0 c[i]C20概念与约束C20引入的概念Concepts使模板编程更加清晰和易用。基础概念#includeconcepts// 定义概念templatetypenameTconceptNumericstd::is_arithmetic_vT;templatetypenameTconceptAddablerequires(T a,T b){{ab}-std::convertible_toT;};templatetypenameTconceptPrintablerequires(T t,std::ostreamos){{ost}-std::convertible_tostd::ostream;};// 使用概念约束模板templateNumeric TTsquare(T x){returnx*x;}templateAddable TTadd(T a,T b){returnab;}templatePrintable Tvoidprint(constTvalue){std::coutvaluestd::endl;}复杂概念// 容器概念templatetypenameTconceptContainerrequires(T t){typenameT::value_type;typenameT::iterator;{t.begin()}-std::same_astypenameT::iterator;{t.end()}-std::same_astypenameT::iterator;{t.size()}-std::convertible_tosize_t;};// 迭代器概念templatetypenameTconceptForwardIteratorrequires(T it){{it}-std::same_asT;{*it};{itit}-std::convertible_tobool;{it!it}-std::convertible_tobool;};// 使用templateContainer CvoidprocessContainer(constCcontainer){for(constautoitem:container){std::coutitem ;}}概念组合// 组合概念templatetypenameTconceptSignedIntegralstd::integralTstd::signed_integralT;templatetypenameTconceptFloatingOrIntegralstd::floating_pointT||std::integralT;// 约束类模板templatetypenameTrequiresstd::integralT||std::floating_pointTclassCalculator{T value;public:Calculator(T v):value(v){}TgetValue()const{returnvalue;}};// 或者使用概念templateFloatingOrIntegral TclassCalculator2{T value;public:Calculator2(T v):value(v){}TgetValue()const{returnvalue;}};概念的优势// 传统SFINAE方式难以理解的错误信息templatetypenameTstd::enable_if_tstd::is_arithmetic_vT,ToldStyle(T a,T b){returnab;}// 使用概念清晰的错误信息templatestd::arithmetic TTnewStyle(T a,T b){returnab;}// 错误时// oldStyle(hello, world); // 错误复杂的SFINAE错误信息// newStyle(hello, world); // 错误清晰的不满足arithmetic概念性能优化与最佳实践1. 减少模板实例化// 不好每个N都会实例化一次templatesize_t NvoidprocessArray(int(arr)[N]){// 大量代码...}// 好只实例化一次voidprocessArrayImpl(int*arr,size_t n){// 大量代码...}templatesize_t NvoidprocessArray(int(arr)[N]){processArrayImpl(arr,N);}2. 使用if constexpr减少代码膨胀// C17 if constexprtemplatetypenameTvoidprocess(T value){ifconstexpr(std::is_integral_vT){// 只有T是整数时才编译这段代码std::coutInteger: valuestd::endl;}elseifconstexpr(std::is_floating_point_vT){// 只有T是浮点数时才编译这段代码std::coutFloat: valuestd::endl;}else{// 其他类型std::coutOther: valuestd::endl;}}3. 避免不必要的递归// 不好深度递归可能导致编译时间过长templateintNstructFib{staticconstexprintvalueFibN-1::valueFibN-2::value;};// 好使用constexpr函数constexprintfib(intn){inta0,b1;for(inti0;in;i){inttempab;ab;btemp;}returna;}4. 使用类型别名简化代码// 使用using简化类型templatetypenameTusingRemoveCVRefstd::remove_cv_tstd::remove_reference_tT;templateboolB,typenameTvoidusingEnableIftypenamestd::enable_ifB,T::type;// C14及以后的标准库已提供_t后缀templatetypenameTusingRemovePointerstd::remove_pointer_tT;5. 模板参数推导// C17类模板参数推导CTADtemplatetypenameTclassContainer{T value;public:Container(T v):value(v){}};// C17之前Containerintc1(42);// C17及以后Containerc2(42);// 自动推导为Containerint// 自定义推导指南templatetypenameTContainer(T)-ContainerT;templatetypenameTContainer(T*)-ContainerT;// 指针退化为值类型6. 编译期优化技巧// 使用constexpr变量而非枚举templatetypenameTstructTraits{// 不好enum{valuesizeof(T)};// 好staticconstexprsize_t valuesizeof(T);};// 使用内联变量C17templatetypenameTinlineconstexprsize_t size_vsizeof(T);// 使用constexprsize_t ssize_vint;// 更简洁7. 避免常见陷阱// 陷阱1依赖名称查找templatetypenameTclassDerived:publicBaseT{voidfoo(){// 错误bar不是依赖名称bar();// 正确方式1使用this-this-bar();// 正确方式2使用BaseT::BaseT::bar();// 正确方式3using声明usingBaseT::bar;bar();}};// 陷阱2typename关键字templatetypenameTvoidfoo(){// 错误编译器不知道iterator是类型还是静态成员T::iterator it;// 正确使用typenametypenameT::iterator it;}// 陷阱3template关键字templatetypenameTvoidfoo(Tobj){// 错误编译器不知道get是模板函数obj.getint();// 正确使用template关键字obj.templategetint();}8. 调试技巧// 打印类型信息templatetypenameTvoidprintType(){std::cout__PRETTY_FUNCTION__std::endl;}// 编译期断言templatetypenameTvoidcheckSize(){static_assert(sizeof(T)8,Type too large!);}// 使用type_traits检查templatetypenameTvoidvalidate(){static_assert(std::is_trivially_copyable_vT,T must be trivially copyable);static_assert(std::is_standard_layout_vT,T must have standard layout);}// 强制编译错误以查看类型templatetypenameTstructShowType;// ShowTypedecltype(expr) x; // 编译错误会显示T的类型总结与进阶路线核心要点回顾模板基础函数模板、类模板、模板参数类型操作类型萃取、SFINAE、enable_if编译期计算constexpr、模板递归变参模板参数包、折叠表达式特化全特化、偏特化高级技术类型列表、表达式模板现代特性概念、if constexpr、CTAD附录常用元编程模式速查// 1. 类型判断std::is_same_vT,Ustd::is_base_of_vBase,Derivedstd::is_convertible_vFrom,To// 2. 类型修改std::remove_const_tTstd::remove_reference_tTstd::decay_tTstd::add_pointer_tT// 3. 条件类型std::conditional_tCondition,TrueType,FalseType// 4. SFINAEstd::enable_if_tCondition,Tstd::void_tT...// 5. 变参模板sizeof...(Args)(args...)// 折叠表达式// 6. 完美转发std::forwardT(arg)// 7. 类型推导decltype(expr)autodecltype(auto)// 8. 编译期计算constexprifconstexpr// 9. 概念C20templatestd::integral Trequiresstd::is_signed_vT