概述
前文回顾:
C++ 泛型编程(一) 基本概念
C++ 泛型编程(二) 函数模版
C++ 泛型编程(三) 模版实参推断
C++ 泛型编程(四) 类模板
模版重载
函数模版可以被另一个模版或者一个普通非模版函数重做;名字相同的函数必须具有不同数量或者类型的参数。
- 根据参数推断只有一个版本是可行的,则选择该版本
- 都是可行的,匹配更精确的版本
- 都是精确匹配,选择特化版本
- 普通函数可以匹配,选择普通函数
- 通过空模板实参列表限定只匹配模板
模版特例化
-
概念
①.特例化:模板,代表了一种泛化的语义,与之相对的就是特化语义。特例化,使得我们能为某些特定的类型专门提供一份特殊实现;特例化本质上是我们顶替了编译器的工作,我们帮编译器做了类型推导。
②.全特化:本质上是一个实例,我们必须为模版中每个参数都提供实参。使用关键字 template 加空尖括号对 <> 定义。
③.偏特化:本质上还是一个模板,只是原来模板的一个子集。
-
函数模版特例化
①.定义
函数模版的不存在偏特化,偏特化即为模版的重载。
template<class T> T add(T a, T b) { return a + b;} //特例化版本,template<> template< > double add(double a, double b) { return a + b; } //重载版本,还是模版 template<class T1> T1 add(T1* a, T1* b) { return *a + *b; }
②.头文件
模版及其特例化版本应该声明在同一个头文件中,所有同名模版的声明应该放在特例化版本之前。
-
类模版特例化
①.类模版全特化
跟函数模板一样,全特化是一个实例,当编译器匹配时会优先匹配参数一致的实例。
//类模版 template<class T> class A { public: explicit A(T val) : t(val) { } T add(T x) { return t + x; } privete: T t; }; //全特化 template< > class A<char*> // 一个全特化的模板类A { public: explicit A(char* val) : t(val) { } char* add(char* x) { return strcat(t, x); } private: char* t; };
②.偏特化-指定部分参数
template<class T1, class T2> // 普通版本,有两个模板参数 class B { ..... }; template<class T2> // 偏特化版本,指定其中一个参数,即指定了部分类型 class B<int , T2> { ..... };
③.偏特化-指定参数形式
template<class T> // 普通版本 class B { ..... }; template<class T> //这个偏特化版本只接收指针类型的模板实参 class B<T*> { ..... };
③.特例化成员
我们也可以只特例化特定成员函数而不是特例化整个模版。
//类模版 template <typename T> class FOO { public: FOO(const T &t = T()):mem(t){} void Bar(){} private: T mem; } template<>//全特化 void FOO<int>::Bar()//特例化 FOO<int> 的一个成员 { }
可变参数模版
-
概念
①.可变参数模版:就是可以接受可变数据参数的模版函数和模版类,即参数数量、以及每个参数的类型都未知且各不相同。
②.参数包:可变数目的参数称为参数包,用省略号来表示一个包。
③.模版参数包:表示零个或者多个模版参数,用 typename… 声明。
④.函数参数包:表示零个或者多个函数参数。
⑤.sizeof…:获取参数包内参数的数量
⑥:Pattern…:以某一模式展开参数包,用省略好触发扩展操作。
-
定义可变参数模版
可变参数模版通常是递归的,参数包Args …在展开的过程中递归调用自己,没调用一次参数包中的参数就会少一个, 直到所有参数都展开为止。
//Args 是一个模版参数包,表示零个或者多个模版类型的参数 //rest 是一个函数参数包,表示零个或者多个函数参数 template<typename T, typename... Args> //函数每次分解出一个 val,剩下的再构成一个包 //模版参数扩展模式:const Args &,对包中每个参数取相同的操作 //等价于:void print(const T &val, const T1 &t1,const T2 &t2,const T3 &3,const T4 &t4,...) void print(const T &val, const Args &... rest) { //每次打印一个参数 cout << val << endl; //递归继续分解 //函数参数扩展模式:rest //等价于print(rest1,rest2,rest3,rest4,...) print(rest...); } //递归终点 void print() {}
-
转发参数包
可变参数函数也可以将它的参数转发给其他函数。模版参数包扩展为一个右值引用的列表,函数参数扩展为一个用 forward 保持类型不变的一个列表。
template<typename... Args> //模版参数扩展模式:Args&&,扩展为右值引用列表 void fun(Args&&... rest) { //函数参数扩展模式:forward<Args>(rest),对每个参数取相同操作 work(std::forward<Args>(rest)...); }
最后
以上就是迷你小虾米为你收集整理的C++ 泛型编程(五) 模版重载与特例化的全部内容,希望文章能够帮你解决C++ 泛型编程(五) 模版重载与特例化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复