函数模板 类模板 一篇详细解析!!看这一篇就够了!!

张开发
2026/5/2 17:33:29 15 分钟阅读

分享文章

函数模板  类模板 一篇详细解析!!看这一篇就够了!!
文章目录模板初探函数模板类模板模板实例化隐式实例化显式实例化模板特化函数模板全特化:类模板全特化类模板偏特化推荐阅读参考链接先贴点东西当然文章末尾也有一些推荐阅读的。这里只介绍了基础的模板操作模板还有很多高级玩法比如成员函数模板内部类模板等不过这些都不常见感兴趣的可以看https://en.cppreference.com/w/cpp/language/template_specialization还有个有意思的知识点不只可以为普通类型使用using起别名其实还可以给模板起别名也是使用using具体可以看https://en.cppreference.com/w/cpp/language/type_alias除了函数模板和类模板在C14中还引入了变量模板但是不常用感兴趣的可以看https://en.cppreference.com/w/cpp/language/variable_template模板初探学C的朋友应该都知道多态多态分为运行时多态和编译时多态其中模板可以粗浅理解为是编译时多态的其中一种方式。模板是一种通用的代码框架允许在编写代码时使用占位符通常是类型或值在实际使用时再指定具体的类型或值。使用模板进行泛型编程可以认为是用一种无关于特定类型的方式来编写代码。模板大体分为函数模板与类模板其中还有些主要的特性比如全特化、偏特化、SFINAE等。模板的声明以关键字 template 开头后跟模板参数列表。模板参数可以是类型参数typename 或 class现在一般都是使用 typename或非类型参数如整数、指针等。这篇文章主要介绍下函数模板与类模板的使用。函数模板函数模板与类模板的声明比较类似都是使用 template 关键字还是直接看示例代码吧。#includeiostream#includestring// 定义模板函数 MaxtemplatetypenameTTMax(Tconsta,Tconstb){returnab?a:b;}intmain(){// 1. 整数比较std::coutMax(1, 2): Max(1,2)std::endl;// 2. 浮点数比较std::coutMax(1.2, 2.3): Max(1.2,2.3)std::endl;// 3. 标准库字符串比较 (按字典序)std::coutMax(\1.2\, \2.3\): Max(std::string(1.2),std::string(2.3))std::endl;return0;}编译命令:g demo.cpp -o demo ./demo运行结果:Max(1,2):2 Max(1.2,2.3):2.3 Max(1.2,2.3):2.3T 起到一个类似占位符的作用使用时传入的是什么类型它就会规定 T 就是这个类型。template 用于声明这是一个模板typename 用来表明 T 是一个泛型类型。也有很多模板的声明不是使用 typename而是使用的 class区别不大。大体语法如下:templatetypenametyperet-typefuncname(parameter list){// function}类模板再举一个类模板的示例:#includeiostream#includevectortemplatetypenameTclassQueue{public:voidPush(constTt){elems.emplace_back(t);}TFront(){returnelems.front();}voidPopFront(){elems.erase(elems.begin());}size_tSize(){returnelems.size();}boolEmpty(){returnelems.empty();}private:std::vectorTelems;};intmain(){Queueintq;q.Push(1);q.Push(2);while(!q.Empty()){std::coutq.Front()std::endl;q.PopFront();}std::cout\n;Queuefloatq2;q2.Push(1.1);q2.Push(2.1);while(!q2.Empty()){std::coutq2.Front()std::endl;q2.PopFront();}}编译命令:g demo.cpp -o demo ./demo运行结果:1 2 1.1 2.1觉得上面的示例复杂可以看下面这个示例可能更简单一些:#includeiostream#includevectortemplatetypenameP,typenameQclassA{public:A(P p,Q q):p_(p),q_(q){}voidPrint(){std::coutp p_ q q_std::endl;}private:P p_;Q q_;};intmain(){Aint,doublea(1,3.3);a.Print();Aint,std::stringb(2,dsds);b.Print();}编译命令:g demo.cpp -o demo ./demo运行结果:p 1 q 3.3 p 2 q dsd s这里可以看到类模板的格式类似于下面这样:templatetypenametypeclassclassname{};再看下默认模板参数:就像函数可以有默认参数一样模板也可以有默认参数比如:#includeiostream#includestringtemplatetypenameP,typenameQintclassA{public:A(P p,Q q):p_(p),q_(q){}voidPrint(){std::coutp p_ q q_std::endl;}private:P p_;Q q_;};intmain(){Aint,doublea(1,3.3);a.Print();Aint,std::stringb(2,dsds);b.Print();Aintc(1,2);c.Print();}编译命令:g demo.cpp -o demo ./demo运行结果:p 1 q 3.3 p 2 q dsd s p 1 q 2模板实例化模板的实例化是指编译器根据模板生成具体的函数或类的过程。模板实例化可以是隐式的由编译器自动完成或显式的由程序员指定。隐式实例化intamax(3,5);// 编译器隐式实例化maxintdoublebmax(3.5,2.5);// 编译器隐式实例化maxdouble显式实例化templateintmaxint(int,int);// 显式实例化maxinttemplatedoublemaxdouble(double,double);// 显式实例化maxdouble模板特化模板的特化是指为特定的类型或值提供特殊的实现。分为全特化和偏特化。全特化模板的所有参数指定具体的类型或值。偏特化模板的部分参数指定具体的类型或值。看模板全特化和偏特化的示例代码。函数模板全特化:#includeiostream#includestringtemplatetypenameTTMax(Tconsta,Tconstb){std::coutMax a b \n;returnab?a:b;}templateintMax(intconsta,intconstb){std::coutMax a b full specialization \n;returnab?a:b;}intmain(){std::coutMax(1,2)std::endl;std::coutMax(1.2,2.3)std::endl;std::coutMax(std::string(1.2),std::string(2.3));}编译命令:g demo.cpp -o demo ./demo运行结果:Max a b full specialization 2 Max a b 2.3 Max a b 2.3类模板全特化#includeiostream#includestring// 1. 必须先定义主模板 (Primary Template)templatetypenameT1,typenameT2classA{public:A(T1 p,T2 q):p_(p),q_(q){}voidPrint(){std::coutPrimary Template - p: p_ q: q_std::endl;}private:T1 p_;T2 q_;};// 2. 然后定义全特化版本 (Full Specialization)// 当两个参数都是 std::string 时执行这个版本templateclassAstd::string,std::string{public:A(std::string p,std::string q):p_(p),q_(q){}voidPrint(){std::coutSpecialized Template (string, string) - p: p_ q: q_std::endl;}private:std::string p_;std::string q_;};intmain(){// 匹配主模板 int, doubleAint,doublea(1,3.3);a.Print();// 匹配主模板 int, std::stringAint,std::stringb(2,dsds);b.Print();// 匹配特化模板 std::string, std::stringAstd::string,std::stringc(hello,world);c.Print();return0;}编译命令:g demo.cpp -o demo ./demo运行结果:Primary Template - p: 1 q: 3.3 Primary Template - p: 2 q: dsd s Specialized Template(string string) - p: hello q:world类模板偏特化#includeiostream#includestring// 1. 必须先定义主模板templatetypenameT1,typenameT2classA{public:A(T1 p,T2 q):p_(p),q_(q){}voidPrint(){std::coutPrimary Template p: p_ q: q_std::endl;}private:T1 p_;T2 q_;};// 2. 偏特化版本当第二个参数固定为 std::string 时templatetypenamePclassAP,std::string{public:A(P p,std::string q):p_(p),q_(q){}voidPrint(){std::coutPartial specialization p: p_ q: q_std::endl;}private:P p_;std::string q_;};intmain(){// 匹配主模板因为第二个参数是 double不是 std::stringAint,doublea(1,3.3);a.Print();// 匹配偏特化因为第二个参数是 std::stringAint,std::stringb(2,special);b.Print();// 匹配偏特化第一个参数是 double第二个是 std::stringAdouble,std::stringc(4.5,test);c.Print();return0;}编译命令:g demo.cpp -o demo ./demo运行结果:Primary Template p: 1 q: 3.3 Partial specialization p: 2 q : special Partial specialization p: 4.5 q : test⚠️注意:类模板可以全特化也可以偏特化函数模板只能全特化不可以偏特化想要达到偏特化效果直接使用函数重载就好了。编译器优先匹配特化的类型然后才会找通用模板做匹配。推荐阅读https://docs.microsoft.com/en-us/cpp/cpp/templates-cpp?viewmsvc-170参考链接https://en.cppreference.com/w/cpp/language/partial_specializationhttps://en.cppreference.com/w/cpp/language/template_specializationhttps://en.cppreference.com/w/cpp/language/templates

更多文章