模板特化与局限性
内容简介
模板能表达通用逻辑,但不是所有类型都天然支持同一套操作。遇到特定类型需要特殊处理时,可以使用重载、特化或 concepts。
模板的局限性
这个模板要求 T 支持赋值:
template <typename T>
void copy_value(T& a, const T& b)
{
a = b;
}如果传入不支持赋值的类型,就无法编译。
这个模板要求 T 支持 >:
template <typename T>
T max_value(T a, T b)
{
return a > b ? a : b;
}如果 T 是自定义类型,并且没有定义比较逻辑,也无法编译。
函数模板特化
普通模板:
template <typename T>
bool equal(T a, T b)
{
return a == b;
}对 C 风格字符串特殊处理:
template <>
bool equal<const char*>(const char* a, const char* b)
{
return std::strcmp(a, b) == 0;
}原因:const char* 的 == 比较的是地址,不是字符串内容。
类模板特化
template <typename T>
class Printer {
public:
void print(const T& value)
{
std::cout << value << '\n';
}
};
template <>
class Printer<const char*> {
public:
void print(const char* value)
{
std::cout << (value ? value : "(null)") << '\n';
}
};偏特化
类模板支持偏特化,函数模板不支持偏特化。
template <typename T>
class Storage {
};
template <typename T>
class Storage<T*> {
// 专门处理指针类型
};现代替代:concepts
C++20 可以用 concepts 直接写出模板要求:
template <typename T>
concept Addable = requires(T a, T b) {
a + b;
};
template <Addable T>
T add(T a, T b)
{
return a + b;
}最佳代码实践
- 简单差异优先用函数重载。
- 类型族差异可以考虑类模板偏特化。
- C++20 后复杂约束优先用 concepts。
- 不要用特化掩盖设计问题,特化越多,模板越难维护。
错误用法
template <typename T>
bool less_than(T a, T b)
{
return a < b; // 假设所有类型都支持 <
}问题:模板没有说明类型要求,错误会在实例化时暴露,报错可能很长。
注意事项
- 模板的“通用”建立在类型满足操作要求的前提上。
- 特化是给特定类型开分支,不是普通 if。
- 泛型代码越底层,越需要把类型要求写清楚。