从接受类型的角度
类模板:全集R
模板偏特化(部分特化):为全集的一个子集A
模板全特化:为R中的一个"点",或者说为R中的一个元素
匹配规则:越特化匹配优先级越高(见下面例子)
98a9da6a-01af-4fc4-83ad-91b7ca549699-image.png
1.类模板// R template<typename T> class A {}; // 类模板是能接受任意类型,A后面不需要(不能)任何处理 2.模板偏特化(局部特化)可以接受任意类型
// A template<typename T> class A<T *> {}; // 类模板A的偏特化版本,在A后指出特化的范围 3.模板全特化可以接受任意指针类型
template<> class A<int> {} // 类模板A的全特化版本(已经是类模板的一个实例了),在A后直接指出明确类型int 4.例子: #include <iostream> #include <string> using namespace std; template<typename T> class A { public: A() { cout << "R" << endl; } }; /* 注释1 -- 接受指针 template<typename T> class A<T *> { public: A() { cout << "A" << endl; } }; */ /* 注释2 -- 接受int template<> class A<int> { public: A() { cout << "int" << endl; } }; */ int main() { A<string> r; // 1 A<char *> a; // 2 A<int> i; // 3 return 0; } 5.测试不同情况:指定接受int类型
当只有一个类模板(可接受任意类型R)存在时,1, 2, 3都使用类模板实例化
v2-a53836d6d2a913d69c2fd90b0dd4371f_1440w.png
注释1是接受所以指针类型(R的子集A),所以称其为类模板A的偏特化(范围特化)。即把类模版A所能接受的指针类型单独处理(实例化)。当取消注释1时:char * 将由这个模板类A的偏特化版本(范围特化,局部特化)处理。
v2-2bd02b7f6a4dbb5cdbc586f98d76b92b_1440w.png
注释2只接受int类型的参数(可以看出是全局R中的一个元素)。当你用int实例化A时,将会由这个全特化版本来实现(而不会使用可以接受任意类型的版本(泛化版))。
v2-6a08120bfe6da8471d8fb374b2665a65_1440w.png
二、类模板与其模板特化的应用 用模板的偏特化 实现一个 能移除任意类型const属性的模板类:remove_const 主要功能和用法: 功能: 给remove_const一个类型后 --1.(情况1)如果这个类型没有const属性则获得这个类型本身。 --2.(情况2)如果这个类型有const属性则移除它。 用法: remove_const<Type>::type 使用场景: 当拿到一个未知变量时,想获得这个变量(或对象)的非const的类型 1.实现情况1#include <iostream> #include <type_traits> template<typename T> struct remove_const { using type = T; }; int main() { int a = 1; const int b = 2; remove_const<decltype(a)>::type aa = 3; remove_const<decltype(b)>::type bb = 4; std::cout << std::is_same<decltype(aa), int>::value << std::endl; std::cout << std::is_same<decltype(bb), int>::value << std::endl; return 0; }似乎没做什么事,aa是int符合情况1。但情况2不符合,bb没有变成int。
运行结果:
v2-7a36de2df8473699ecc173f27351c876_1440w.png
从上面的实现可以看出,当传给模板的参数是带const类型时它还会返回带const属性的类型。同时从remove_const的定义也可以看出他是个 复读机 你给他什么类型他就给你什么类型。
这时候可以使用上面介绍的偏特化的性质,来把带有带const的类型这个子集从全集中分离出来 特殊处理。如下:
#include <iostream> #include <type_traits> template<typename T> struct remove_const { using type = T; }; template<typename T> struct remove_const<const T> { using type = T; }; int main() { int a = 1; const int b = 2; remove_const<decltype(a)>::type aa = 3; remove_const<decltype(b)>::type bb = 4; std::cout << std::is_same<decltype(aa), int>::value << std::endl; std::cout << std::is_same<decltype(bb), int>::value << std::endl; return 0; }运行结果:
给带const的类型,写了一个特化版本。所以当remove_const接受一个带const的类型时,就会通过这个偏特化版本实例化,由于这个偏特化版本把const从类型中分离出来了,则这里的T就是没有const的类型,从而实现去除类型const的功能。
v2-d337e4dc338fc9a90fcfa7ef9db27804_1440w.png
三、模板特化存在性问题一个类模板的特化,是对某一个类模板的子集做特化处理的。而它不能"独立存在"。既只有存在一个类模板X, 才能存在对它特化的版本。
template<typename T> class A<T *> {}; int main() { return 0; }v2-1023f2d6ec20e5efa6300629068527d6_1440w.png