C++ 模板

C++ 的 模板(Template)提供了一种在编译期对类型和常量进行参数化的机制,是实现泛型编程(Generic Programming)的核心。模板能够让同一份代码适用于多种类型,消除重复,同时还能借助特化和约束,实现高度灵活的库设计。下面分章介绍其主要形式与高级特性。


1. 函数模板

定义一族同名函数,编译器在调用时根据实参类型自动生成对应版本:

// 通用 swap
template<typename T>
void swap_(T& a, T& b) {
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

// 使用
int x = 1, y = 2;     swap_(x, y);
std::string s1 = "A", s2 = "B"; swap_(s1, s2);
  • 模板参数列表template<typename T>(或 template<class T>
  • 参数推导:调用时可省略显式模板实参 swap_<int>(x,y),编译器自动推导 T=int

2. 类模板

将类型参数化的类定义,可实例化成不同类型版本:

template<typename T>
class Box {
    T value_;
public:
    explicit Box(const T& v): value_(v) {}
    T get() const { return value_; }
    void set(const T& v) { value_ = v; }
};

// 使用
Box<int>   bi(42);
Box<double> bd(3.14);
  • 类模板可以有多个模板参数:template<typename T, size_t N>
  • 支持默认模板参数:template<typename T = int> class Vec { … };

3. 非类型模板参数

模板参数不仅限于类型,也可是整型、指针等常量:

template<typename T, std::size_t N>
struct FixedArray {
    T data[N];
    constexpr std::size_t size() const { return N; }
};

FixedArray<int, 10> arr;

非类型参数在编译期已知,可用于尺寸、策略选择等。


4. 模板特化

4.1 完全特化

为某个特定类型提供专门实现:

template<typename T>
struct Printer {
    static void print(const T& x) { std::cout << x; }
};

// 对 char* 专门化
template<>
struct Printer<char*> {
    static void print(char* s) { std::cout << '"' << s << '"'; }
};

4.2 偏特化(仅对类模板)

对一类模板参数组合重载:

// 通用版本
template<typename T, typename U>
struct Pair { /*…*/ };

// 当两个类型相同时的偏特化
template<typename T>
struct Pair<T, T> { /*…*/ };

函数模板不支持偏特化,可用重载或 enable_if 替代。


5. 变参模板(C++11 起)

允许任意数量的模板参数和函数参数:

// 函数变参模板
template<typename... Args>
void log_all(Args&&... args) {
    (std::cout << ... << args) << "\n";  // fold expression
}

// 使用
log_all(1, " + ", 2.5, " = ", 3.5);
  • typename... Args:参数包
  • 展开(expr(args),…) 或 C++17 的折叠表达式

6. SFINAE 与 std::enable_if

“Substitution Failure Is Not An Error” 允许在模板参数推导失败时剔除某些重载,实现条件化重载:

#include <type_traits>

template<typename T>
auto foo(T x) 
  -> std::enable_if_t<std::is_integral_v<T>, void> {
    std::cout << "integral\n";
}

template<typename T>
auto foo(T x) 
  -> std::enable_if_t<std::is_floating_point_v<T>, void> {
    std::cout << "floating\n";
}

C++20 中可用 概念(Concept) 更直观地约束模板。


7. C++20 概念与约束

概念(concept)提供了第一类语法支持的模板约束,替代繁琐的 enable_if

template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::same_as<T>;
};

template<Addable T>
T add(T a, T b) {
    return a + b;
}
  • requires 表达式 用于检查操作合法性
  • 调用 add(std::string, std::string) 合法,但 add(int, std::string) 编译时报错。

小结

  • 函数模板类模板 是实现类型无关代码的手段;
  • 非类型参数模板特化变参模板 大幅提升灵活性;
  • SFINAE 和 概念 为模板添加编译期约束,保证更早发现错误;
  • 合理运用这些特性,可以构建高性能、可重用且类型安全的泛型库。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注