这里提到了模板特化,那么什么是模板特化?
模板特化本质是 “为模板的特定参数组合提供定制化实现”
一.先明确概念
模板特化是对 “通用模板” 的补充:
通用模板(主模板):处理大部分参数情况(比如 CompileTimeAdd<A,B> 处理任意 A、B);
特化模板:处理特定参数情况(比如 CompileTimeAdd<0,B> 处理 A=0 的场景);
编译器匹配规则:优先匹配特化模板,匹配不到再用通用模板。

模板特化分为三类,语法复杂度从低到高:
全特化(Full Specialization):所有模板参数都固定;
偏特化(Partial Specialization):部分模板参数固定(仅类模板支持);
函数模板特化:函数模板的特化(语法和类模板略有不同)。

二、全特化
1. 类模板全特化

template<int A, int B>
//1.通用模板:处理任意A,B的加法
struct CompileTimeAdd {
	static const int value = CompileTimeAdd<A - 1, B + 1>::value;
};
//2.全特化模板:处理A=0的情况(递归终止)
template<>//全特化:无固定参数
struct CompileTimeAdd<0, 5> {
	static const int value = 5;
};
template<int B>
struct CompileTimeAdd<0, B> {
	static const int value = B;
};
int main() {
	cout << CompileTimeAdd<3, 5>::value << endl; //递归到最后匹配全特化<0,5>,返回5
	cout << CompileTimeAdd<2, 6>::value << endl; //递归到最后匹配偏特化<0,B>,返回8
	return 0;
}

2.函数模板全特化

注:函数模板特化没有偏特化,只有全特化,语法注意:template<> 后直接写函数定义,参数列表要匹配特化类型。

//1. 通用函数模板:打印任意类型
template<typename T>
void print(T val) {
	cout << "通用模板:" << val << endl;
}
//2.函数模板全特化:处理T = string 的情况
template<>
void print<string>(string val) { //显式制定特化类型<string>
	cout << "特化模板(字符串):" << val << endl;
}
//简化写法:可以省略掉<>中的类型
template<>
void print(int val) {
	cout << val << endl;
}
int main() {
	print(10);    // 匹配int特化,输出:特化模板(整数):10
	print("abc"); // 匹配通用模板,输出:通用模板:abc
	print(string("hello")); // 匹配string特化,输出:特化模板(字符串):hello
	return 0;
}

三、偏特化(仅类模板支持,部分参数固定)

偏特化是 “只固定一部分模板参数,剩下的仍为通用”,核心语法:template<剩余通用参数> + 类名<固定参数, 通用参数>。

1.固定部分非类型参数

// 通用模板:两个非类型参数A、B
template<int A, int B>
struct CompileTimeAdd {
	static const int value = CompileTimeAdd<A - 1, B + 1>::value;
};

// 偏特化:固定A=0,B仍为通用参数
template<int B> // 剩余通用参数:B
struct CompileTimeAdd<0, B> { // 固定第一个参数为0
	static const int value = B;
};
// 全特化
template<>
struct CompileTimeAdd<0, 5> {
	static const int value = 5;
};

2.固定部分类型参数

//通用模板:两个类型参数T,U
template<typename T, typename U>
struct MyTemplate {
	void show() {
		cout << "通用:T=" << typeid(T).name() << "U=" << typeid(U).name() << endl;
	}
};
// 偏特化:固定T=int,U仍为通用
template<typename U>
struct MyTemplate<int, U> {
	void show() {
		cout << "偏特化:T= int" << typeid(U).name() << endl;
	}
};

// 偏特化:固定U=string,T仍为通用
template<typename T>
struct MyTemplate<T, string> {
	void show() { cout << "偏特化:T=" << typeid(T).name() << ", U=string" << endl; }
};
int main() {
	MyTemplate<double, float>().show();    // 通用:T=double, U=float
	MyTemplate<int, float>().show();       // 偏特化:T=int, U=float
	MyTemplate<double, string>().show();   // 偏特化:T=double, U=string
	return 0;
}

3.对指针 / 引用类型偏特化(常用)

// 通用模板:任意类型T
template<class T>
class MyTemplate1 {
public:
	void show() {
		cout << "T=" << typeid(T).name() << endl;
	}
};
// 偏特化:T为指针类型
template<class T>
class MyTemplate1 <T*>{
public:
	void show() {
		cout << "T=" << typeid(T).name() <<"*" << endl;
	}
};
// 偏特化:T为引用类型
template<class T>
class MyTemplate1 <T&> {
public:
	void show() {
		cout << "T=" << typeid(T).name() <<"&" << endl;
	}
};
int main() {
	MyTemplate1<int>().show();        // 通用:T=int
	MyTemplate1<int*>().show();       // 偏特化:T=指针(int*)
	MyTemplate1<int&>().show();       // 偏特化:T=引用(int&)
	return 0;
}

这里是对模板特化的理解,而萃取编程呢是在模板特化的基础上对类型的萃取。

四. 什么是类型萃取?

类型萃取(Type Traits) 是 C++ 模板元编程的核心技术 —— 简单来说,它是一套在编译期查询 / 修改类型属性的工具(主要在<type_traits>头文件中),能在编译期判断 “某个类型是否是指针 / 引用 /const”、“两个类型是否相同”,或把类型 “从指针转为普通类型”、“从非 const 转为 const” 等。

类型萃取的作用是:把运行时的类型判断,提前到编译期完成,既提升程序效率,又能通过编译期分支(SFINAE)实现更灵活的模板逻辑。

下面举几个例子:

1.比较简单一点的,判断是否是指针的萃取器

//1.主模板:默认所有类型都不指针
template<class T>
struct is_pointor {
	static constexpr bool value = false;
};
// 2. 模板特化:针对指针类型的特殊处理
// T* 匹配所有指针类型(int*、string*、double*等)
template<typename T>
struct is_pointer<T*> {
	static constexpr bool value = true;
};
// 测试代码
int main() {
	// 萃取int的特征:是不是指针?
	cout << "int 是否是指针:" << boolalpha << is_pointer<int>::value << endl;   // false
	// 萃取int*的特征:是不是指针?
	cout << "int* 是否是指针:" << boolalpha << is_pointer<int*>::value << endl;  // true
	// 萃取string*的特征:是不是指针?
	cout << "string* 是否是指针:" << boolalpha << is_pointer<string*>::value << endl; // true
	return 0;
}

2.稍微进阶一点,判断是否是整数类型(int/short/long 等)

//主模板
template<class T>
struct is_interal {
	static constexpr bool value = false;
};
template<>
struct is_interal <int>{
	static constexpr bool value = true;
};
template<>
struct is_interal<short> {
	static constexpr bool value = true;
};
template<>
struct is_interal<long> {
	static constexpr bool value = true;
};
template<>
struct is_interal<long long> {
	static constexpr bool value = true;
};
int main() {
	cout << is_interal<long>::value << endl;
}

3.萃取类型的 “原始类型”

// 1. 移除const修饰的萃取器
// 主模板:默认类型就是自身(非const类型)
template<typename T>
struct Remove_const {
	using type = T; // 用typedef/using暴露萃取的类型
};

// 特化:针对const T类型,移除const
template<typename T>
struct Remove_const<const T> {
	using type = T;
};

// 2. 移除指针修饰的萃取器
// 主模板:默认类型就是自身(非指针类型)
template<typename T>
struct Remove_pointer {
	using type = T;
};

// 特化:针对T*类型,移除指针
template<typename T>
struct Remove_pointer<T*> {
	using type = T;
};
// 测试
int main() {
	// 萃取const int的原始类型:int
	Remove_const<const int>::type a = 10;
	cout << a << endl; // 10

	// 萃取const int*的原始类型:先移除指针→const int,再移除const→int
	Remove_const<Remove_pointer<const int*>::type>::type b = 20;
	cout << b << endl; // 20
	return 0;
}

五. 类型萃取的两大核心分类

C++ 标准库(<type_traits>)把类型萃取分为两类,覆盖几乎所有常用场景:

1. 类型查询萃取器(判断类型属性)

用于编译期判断类型的特征,返回bool类型的编译期常量(value)。

2. 类型转换萃取器(修改类型属性)

用于编译期修改类型的特征,返回一个新的类型(通过type成员)。

六. 总结

  1. 类型萃取本质:基于模板特化,在编译期查询 / 修改类型属性的工具;
  2. 核心分类
    • 查询型:判断类型特征(is_pointeris_constis_same);
    • 转换型:修改类型特征(remove_constremove_pointerdecay);
  3. 核心价值:编译期完成类型判断 / 转换,提升效率,支持泛型编程的灵活逻辑;
  4. 常用场景:模板参数约束、编译期分支、统一处理不同类型。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐