ARTICLE · 1211338
模板特化②:函数全特化、重载和 requires
“给某种类型特殊处理”,是一个需求。全特化、重载、约束,是实现需求的不同机制。
这一篇用相似的小例子,把它们分清。基础示例使用 C++17;std::integral 示例需要 C++20。
01 / 真正的函数模板全特化
template<class T>constchar* kind(T){return"generic";}template<>inlineconstchar* kind<int>(int) {return"int specialization";}// kind(7) 使用整数全特化// kind(2.5) 使用主模板的 double 版本这里的 template<> 明确引入显式特化。kind<int> 对应已有的 kind 主模板,函数参数与之匹配。
在适合推导的声明中,函数模板全特化的模板实参列表可以省略;教学时显式写出来,更容易看清它对应哪组实参。
02 / 普通重载增加一个候选函数
template<class T>constchar* pick(T){return"template";}inlineconstchar* pick(int){return"ordinary overload";}整数版本没有 template<>,它是一个普通函数重载。
在这组定义中,pick(7) 会选择普通函数;写成 pick<>(7) 则明确要求模板调用,普通函数不参与这次模板候选选择。
这说明两种写法虽然都能处理整数,但它们在候选集合和调用形式上有区别。
03 / requires 示例属于约束重载
#include<concepts>template<class T>intscore(T){return0;}template<std::integral T>intscore(T){return1;}// score(7) 是 1// score(2.5) 是 0这里有两个函数模板。第二个要求 T 满足整数概念,是更受约束的重载。
在这个简单示例里,整数调用选择第二个,浮点数调用选择第一个。
不能因为它只接受一类类型,就把它称为函数模板全特化。 同理,原稿中用两个 requires 限制加减行为的例子,应称为受约束的函数模板重载。

04 / 全特化不独立加入重载候选
这组定义的顺序是有意安排的:
template<class T>constchar* route(T){return"value";}template<>inlineconstchar* route<int*>(int*) {return"specialized value";}template<class T>constchar* route(T*){return"pointer";}中间的全特化声明出现时,指针重载还没有声明,所以它对应第一个按值接收的主模板。
现在调用:
int* p = nullptr;// route(p) 选择指针主模板,结果是 "pointer"函数重载选择首先比较相关主模板等候选。中间的全特化不会成为一个独立候选,去“打败”后面的指针模板。
因此,不要把“普通函数 → 全特化 → 偏特化 → 主模板”背成一个通用优先级表。这样的表混合了不同机制。

05 / 函数模板不支持偏特化
template<class T>voidinspect(T){}template<class T>voidinspect(T*){}这两个声明是重载关系。第二个不是函数模板偏特化。
如果需求是根据指针、整数、容器等类别选择处理函数,先考虑函数重载与约束;如果需要一个函数体里的编译期分支,也可以考虑 if constexpr。
06 / 成员函数模板有两层参数
template<classT>structA {template<class U>voidf(U)const{}};template<>template<>inlinevoid A<int>::f<double>(double) const {}这个例子把外层 T 指定为 int,把内层 U 指定为 double,因此写两层 template<>。
不要推广成“所有嵌套模板都写两次”。已经全特化的外层和仍然保留参数的内层,需要按实际层次分别判断。系列第 4 篇会再看嵌套类模板。
07 / 写函数定制前,先判断机制
针对一组实参替换已有函数模板的定义,是全特化;增加另一个可调用候选,是重载;限制某个函数模板可接受的实参,是约束。
原始需求可以相似,语法和选择规则仍要分开。下一篇转向真正支持偏特化的类模板与变量模板。
参考:C++ 标准工作草案:显式特化[1]、函数模板重载解析[2]、约束的偏序关系[3]。示例经文字与规则核对,未编译执行。
引用链接
[1]C++ 标准工作草案:显式特化: https://eel.is/c++draft/temp.expl.spec
[2]函数模板重载解析: https://eel.is/c++draft/temp.over
[3]约束的偏序关系: https://eel.is/c++draft/temp.constr.order















































































