资源库最新版在线,seo搜索引擎优化工资,wordpress音乐插件怎么用,平面广告设计要用什么软件有哪些目录10.1 函数模板的引入10.2 调用模板函数10.2.1 显式实例化10.2.2 隐式实例化10.3 模板函数应用实例10.4 C concept#xff08;C20#xff09;10.4.1 一个错误10.4.2 创建10.4.3 使用10.4.4 实例10.5 可变参数模板10.5.1 实现10.5.2 编译器运行可变参数模板10.5.3 可变模板…目录10.1 函数模板的引入10.2 调用模板函数10.2.1 显式实例化10.2.2 隐式实例化10.3 模板函数应用实例10.4 C conceptC2010.4.1 一个错误10.4.2 创建10.4.3 使用10.4.4 实例10.5 可变参数模板10.5.1 实现10.5.2 编译器运行可变参数模板10.5.3 可变模板参数类型10.6 模板元编程10.6.1 例子阶乘与斐波那契10.6.2 Boost MPL库10.6.3 模板元编程是图灵完备的10.6.4 模板元编程的规范化实现10.7 何时用模板10.1 函数模板的引入编写min函数min(106,107);// int, returns 106min(1.2,3.4);// double, returns 1.2min(Jacob,Fabio);// string, returns Fabio方法函数重载intmin(inta,intb){returnab?a:b;}doublemin(doublea,doubleb){returnab?a:b;}std::stringmin(std::stringa,std::stringb){returnab?a:b;}我们可以用模板templatestemplatetypenameTTmin(T a,T b){returnab?a:b;}// 用引用避免拷贝templatetypenameTTmin(constTa,constTb){returnab?a:b;}函数模板VS函数templatetypenameTTmin(T a,T b)// 这是函数模板不是函数minstd::string// 这是一个函数是模板实例化10.2 调用模板函数10.2.1 显式实例化函数模板会自动生成代码intmin(inta,intb){// Compiler generatedreturnab?a:b;// Compiler generated}// Compiler generateddoublemin(doublea,doubleb){// Compiler generatedreturnab?a:b;// Compiler generated}minint(106,107);// Returns 106mindouble(1.2,3.4);// Returns 1.210.2.2 隐式实例化让编译器为我们自动推断类型有点像automin(106,107);// int, returns 106min(1.2,3.4);// double, returns 1.2隐式实例化有可能难以处理1、不好推断具体类型2、两个参数类型不严格匹配会编译报错一种解决方案templatetypenameT,typenameU// 解决两个独立模板参数auto min(constTa,constUb){// 解决auto推导返回值returnab?a:b;}min(106,3.14);// 调用成功TintUdouble返回值为double双模板参数 auto 返回值C14 支持1、解决两个参数类型不严格匹配模板参数从 typename T 改为 typename T, typename U意味着• 第一个参数的类型由 T 推导实参 106 → Tint• 第二个参数的类型由 U 推导实参 3.14 → Udouble• 两个参数类型不再强制统一完美支持不同类型的输入如 intdouble、floatlong 等。2、解决“不好推断具体类型”返回值用 auto 关键字让编译器根据「三元运算符的结果类型」自动推导返回值• 三元运算符 a b ? a : b 中a 是 intb 是 double• C 会遵循「usual arithmetic conversions」常用算术转换将 int 隐式转换为 double最终返回 double 类型• 无需手动指定返回值类型如 decltype(a b ? a : b)auto 直接搞定避免了 “返回值类型与参数类型不匹配” 的问题。10.3 模板函数应用实例迭代器中10.4 C conceptC2010.4.1 一个错误structStanfordID;// How do we compare two IDs?StanfordID jacob{Jacob,jtrb};StanfordID fabio{Fabio,fabioi};minStanfordID(jacob,fabio);// ❌ Compiler error$ g main.cpp --stdc20 main.cpp:9:12: error: invalid operands to binary expression(const StanfordIDandconst StanfordID)returnab ? a:b;~ ^ ~ main.cpp:20:3: note:ininstantiation offunctiontemplate specializationminStanfordIDrequested here minStanfordID(jacob, fabio);^1error generated.编译器实例化我们的模板只有在执行时才抛出错误。编译器仅在实例化后才会发现错误。如何给模板施加类型约束呢10.4.2 创建创建一个Comparable concept使用concept的两个原因更好的编译器错误消息更好的 IDE 支持智能感知 / 自动补全等概念仍是一项新功能STL还未支持它们。截至2025春使用Comparable concepttemplatetypenameTrequires ComparableTTmin(constTa,constTb);// Super slick shorthand for the abovetemplateComparable TTmin(constTa,constTb);10.4.3 使用使用概念concept的前后报错差异10.4.4 实例Concepts 库Iterator concepts10.5 可变参数模板10.5.1 实现可变参数模板通过模板递归实现// 基本案例函数需要停止递归templateComparable TTmin(constTv){returnv;}templateComparable T,Comparable...Args// 可变参数模板匹配0个或多个类型Tmin(constTv,constArgs...args){// 参数打包0个多多个参数autommin(args...);// 打包展开用实际参数替换args...returnvm?v:m;}10.5.2 编译器运行可变参数模板此时编译器为我们自动生成了重载形成了min(a0,a1,a2)另一个模板实例化。继续递归生成 结果生成了下列所有的函数10.5.3 可变模板参数类型可变模板参数类型不必同构format(Queen {}, Protector of the {} Kingdoms, Rhaenyra,7);异构format(Queen {}, Protector of the {} Kingdoms,Rhaenyra,7);// Prints: Queen Rhaenyra, Protector of the 7 Kingdomsstd::coutstd::boolalpha;format(The {} enemy wont {} out the {},true,wait,storm);// Prints: The true enemy wont wait out the stormformat(Winter is coming);// Prints: Winter is coming执行formatvoidformat(conststd::stringfmt){std::coutfmtstd::endl;}templatetypenameT,typename...Argsvoidformat(conststd::stringfmt,T value,Args...args){autoposfmt.find({});if(posstd::string::npos)throwstd::runtime_error(Extra arg);std::coutfmt.substr(0,pos);std::coutvalue;format(fmt.substr(pos2),args...);}在C中std::format是一个 variadic 模板函数用于格式化字符串。当我们实例化instantiateformat时实际上是编译器根据提供的模板参数和函数参数生成具体的函数实例。例子voidformat(conststd::stringfmt){std::coutfmtstd::endl;}templatetypenameT,typename...Argsvoidformat(conststd::stringfmt,T value,Args...args){autoposfmt.find({});if(posstd::string::npos)throwstd::runtime_error(Extra arg);std::coutfmt.substr(0,pos);std::coutvalue;format(fmt.substr(pos2),args...);}format(Lecture {}: {} (Week {}), 9, Templates,5);这是最常见的用法编译器会自动推导模板参数类型从参数推断出类型int, const char*, int编译器生成匹配这些类型的format函数实例formatint, std::string, int()显式指定模板参数第一个类型为int后续参数类型为std::string和int这里T int可变参数包Args [std::string, int]formatstd::string, int()显式指定模板参数T std::stringArgs [int]formatint()只指定了一个模板参数T int没有其他参数Args为空format()无模板参数的基础情况这不是模板实例化而是调用无参数版本的format函数简单来说format模板函数的实例化过程就是编译器根据指定的类型参数或从函数参数推导出的类型生成特定版本的format函数代码以匹配具体的调用需求。这种模板机制让format能够处理各种不同类型和数量的参数。总结编译器使用递归生成任意数量的重载这使我们能够支持任意数量的函数参数。实例化发生在编译时10.6 模板元编程10.6.1 例子阶乘与斐波那契这段代码展示了使用C模板元编程TMP在编译期计算阶乘的方法核心思想是利用模板特化和递归实现编译时计算基础情况templatestructFactorial0{enum{value1};// 0的阶乘定义为1};这是模板的全特化版本当模板参数N0时使用直接定义阶乘结果为1终止递归。递归模板templatesize_t NstructFactorial{enum{valueN*FactorialN-1::value};};通用模板通过递归方式计算N的阶乘 N × (N-1)的阶乘编译器会在编译时展开递归直到触发N0的特化版本。编译期计算特性使用enum是为了在编译期存储常量值。当调用Factorial7::value时编译器会在编译阶段就完成7! 5040的计算运行时直接使用结果这比运行时计算更高效。这种技术展示了模板元编程的核心能力将计算从运行时转移到编译时实现编译期执行代码的效果。这段代码展示了编译期计算阶乘的汇编输出结果核心特点是结果在编译时就已计算完成并直接嵌入到可执行文件中。Factorial7::value是一个模板元编程实现编译器在编译阶段就会计算出 7! 5040汇编代码中直接出现了5040这个值说明没有运行时计算过程程序只是简单地将预计算好的 5040 通过std::cout输出这种方式比运行时计算更高效因为结果已经 “烘焙”(baked in) 到可执行文件中这体现了模板元编程的优势将计算从运行时转移到编译时提高程序执行效率。另一个例子templatestructFibonacci0{enum{value0};};templatestructFibonacci1{enum{value1};};templatesize_t NstructFibonacci{enum{valueFibonacciN-1::valueFibonacciN-2::value};};实际应用在编译时将结果嵌入可执行文件例如阶乘优化矩阵、树和其他数学结构基于策略的设计通过模板传递行为Boost MPL 库10.6.2 Boost MPL库usingnamespaceboost;usingMovempl::vectorMoveUp,MoveRight;usingMoveRotatempl::push_backMove,Rotate45::type;templatetypenameTransformationsvoidapply(Object);applyMove(object);// move object up and rightapplyMoveRotate(object);// move object up/right, rotate 45deg这段代码涉及C元编程Metaprogramming的概念和Boost.MPL库的使用核心解析如下元编程TMP特性TMPTemplate Metaprogramming允许在编译期通过类型进行编程将类型作为数据来操作编译器会为不同的类型组合生成特定代码实现编译期多态和代码生成Boost MPL库是C中最流行的元编程库mpl即MetaProgramming Library提供了类似容器、算法等元编程工具用于在编译期处理类型集合代码解析using Move mpl::vectorMoveUp, MoveRight定义了一个包含MoveUp和MoveRight两种类型的元容器using MoveRotate mpl::push_backMove, Rotate45::type通过元函数push_back在Move基础上添加Rotate45类型生成新的类型集合编译期代码生成template typename Transformations void apply(Object)模板函数根据传入的类型参数生成特定代码applyMove(object)会生成执行上移右移的代码applyMoveRotate(object)会生成执行上移右移45度旋转的代码这种方式的优势是将操作组合的决策移到编译期减少运行时开销同时通过类型系统保证操作的合法性。10.6.3 模板元编程是图灵完备的1. 先明确两个基础概念图灵完备性一个计算系统或语言、工具若能模拟“图灵机”的所有行为即具备“条件分支”“循环或递归”“数据存储”这三大核心能力就能计算任何图灵机可解的问题称为“图灵完备”。简单说能实现“根据条件做不同操作”“重复执行一段逻辑”“保存中间结果”就满足图灵完备的核心要求。TMP即模板元编程C 中的一种特殊编程范式——利用模板的编译期展开机制让代码在“编译阶段”而非“运行阶段”执行计算。例如通过模板特化实现分支、通过递归模板实现循环最终生成编译期确定的结果。2. TMP 如何满足图灵完备的三大条件TMP 之所以是图灵完备的关键在于它在编译期实现了图灵机的核心能力条件分支通过模板特化Template Specialization实现。例如定义一个通用模板再为特定条件如“数值等于 0”写特化版本编译时会根据输入参数匹配对应的模板本质就是“根据条件选择不同逻辑”。// 通用模板默认分支templateintNstructIsZero{staticconstboolvaluefalse;};// 特化模板条件分支N0 时触发templatestructIsZero0{staticconstboolvaluetrue;};循环/递归通过递归模板Recursive Templates实现。利用模板参数的递推如N-1重复展开模板直到触发“终止条件的特化模板”本质是“编译期的循环”。例如计算阶乘编译期确定5! 120// 通用递归模板循环体N! N * (N-1)!templateintNstructFactorial{staticconstintvalueN*FactorialN-1::value;};// 特化模板终止条件0! 1templatestructFactorial0{staticconstintvalue1;};// 编译期计算Factorial5::value 直接等于 120数据存储通过模板参数、静态常量、类型别名实现。模板参数如上述int N可存储数值静态常量static const int value可存储计算结果类型别名using可存储“类型数据”——这些都是编译期的“数据载体”对应图灵机的“纸带存储”。3. 关键结论TMP 虽依赖 C 模板的编译期机制且执行阶段编译期与常规编程语言运行期不同但它完全具备“条件分支、递归循环、数据存储”三大图灵完备核心能力因此可以模拟任何图灵机可解的计算问题即“TMP 是图灵完备的”。注TMP 的“计算”局限于编译期且受编译器模板递归深度、类型复杂度等限制但这是工程实现约束不影响其图灵完备性的理论属性。10.6.4 模板元编程的规范化实现在C20中constexpr和consteval是用于编译期计算的关键字它们将模板元编程的思想制度化让编译期计算更直观constexpr如第一个阶乘函数告诉编译器尽量在编译期运行我。它既可以在编译期执行也能在运行时调用具有灵活性。示例中使用了C17的constexpr if进一步增强了编译期分支能力。consteval如第二个阶乘函数强制要求必须在编译期运行我被称为立即函数。它只能在编译期执行确保计算结果在程序运行前就已确定常用于需要严格编译期保证的场景。两者都简化了编译期计算的实现避免了传统模板元编程的晦涩语法让开发者能更自然地编写可在编译阶段执行的代码如阶乘计算。10.7 何时用模板我希望编译器能自动完成重复性的编码任务——模板函数template function、变长模板variadic templates我想要更好的错误信息——概念concept我不想等到运行时——模板元编程template metaprogramming、constexpr/consteval