一、函数模板:让代码学会"自动适配"

想象一下,你每天要写十几个max()函数,分别处理int/double/string类型。这时候函数模板就像个智能复印机——你只需定义一次,编译器会自动生成对应版本:

// 技术栈:C++17
template<typename T>  // 声明模板参数T
T smartMax(T a, T b) { // 自动推导参数类型
    return (a > b) ? a : b;
}

/* 实际调用示例 */
int main() {
    cout << smartMax(3, 5);       // 实例化int版本
    cout << smartMax(2.7, 1.8);   // 实例化double版本
    cout << smartMax("A", "B");   // 实例化const char*版本
}

应用场景

  • 通用算法(如排序/查找)
  • 容器操作(如打印任意类型数组)
  • 数学计算库(支持多精度运算)

注意事项

  1. 模板定义通常放在头文件中
  2. 类型推导失败时需要显式指定类型(如smartMax<int>(3, 5.5)

二、类模板:打造类型安全的"万能容器"

类模板就像乐高积木,用相同代码结构适配不同数据类型。最经典的例子就是STL中的vector

// 技术栈:C++20
template<typename T, size_t N = 10>  // 默认缓冲区大小
class SmartArray {
private:
    T data[N];  // 泛型存储区
public:
    void set(size_t idx, T value) {
        data[idx] = value;
    }
    T get(size_t idx) const {
        return data[idx];
    }
};

/* 使用示例 */
SmartArray<float> floatArr;  // 存储浮点数
SmartArray<std::string, 5> strArr; // 定制容量

高级技巧

  • 模板参数可以是整型常量(如示例中的N
  • 成员函数可以在类外定义(需加template前缀)
  • 支持嵌套模板(如SmartArray<SmartArray<int>>

三、模板特化:当通用方案遇到特殊情况

有时候通用模板不适用于特定类型,就像万能钥匙打不开保险箱。这时需要模板特化:

// 通用版本
template<typename T>
struct TypeInfo {
    static string name() { return "unknown"; }
};

// 全特化版本(针对double)
template<>
struct TypeInfo<double> {
    static string name() { return "IEEE754浮点数"; }
};

// 偏特化版本(针对指针类型)
template<typename T>
struct TypeInfo<T*> {
    static string name() { return "指针类型"; }
};

实战场景

  1. 优化特定类型的算法性能(如std::vector<bool>特化)
  2. 处理类型特性(如std::is_integral
  3. 接口适配(如网络序列化特殊处理)

四、高级技巧:模板元编程的魔法

模板可以在编译期完成计算,这种技术被称为模板元编程(TMP)。来看个编译期斐波那契数列:

template<int N>
struct Fibonacci {
    static constexpr int value = 
        Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};

// 基础case特化
template<>
struct Fibonacci<0> { static constexpr int value = 0; };

template<>
struct Fibonacci<1> { static constexpr int value = 1; };

/* 使用示例 */
static_assert(Fibonacci<5>::value == 5); // 编译期验证

现代C++改进

  • C++11引入constexpr简化TMP
  • C++17的if constexpr让代码更易读
  • C++20概念(concepts)增强类型约束

五、避坑指南与最佳实践

  1. 错误信息优化:使用static_assert给出友好提示
template<typename T>
void process(T val) {
    static_assert(std::is_arithmetic_v<T>, 
        "只支持数值类型!");
}
  1. 性能取舍
  • 优点:编译期多态零运行时开销
  • 缺点:可能增加编译时间和二进制体积
  1. 设计原则
  • 优先使用函数模板而非宏
  • 模板参数应满足最小约束
  • 复杂逻辑建议拆分为常规函数

总结
C++模板就像瑞士军刀,既能写通用库也能做元编程。掌握特化和SFINAE等技巧后,你会发现编译期其实能完成大半运行时的工作。虽然学习曲线陡峭,但这份投入绝对物超所值。