引言
C++模板不仅支持泛型编程,更藏着一套图灵完备的"编译期语言"------模板元编程(Template Metaprogramming,TMP)。利用模板的递归实例化与特化,我们可以在编译阶段完成数值计算、类型推导乃至生成代码,从而提升运行时性能、增强类型安全。
本文将从零开始,介绍模板元编程的核心概念,并通过可运行 的阶乘与类型列表示例,帮你快速上手。即使你只打算用 constexpr,理解 TMP 也能让你更懂 C++ 模板的工作原理。
核心概念
1. 编译期常量与递归模板
模板元编程的本质是让编译器在实例化模板时执行计算 。以最经典的编译期阶乘为例:
cpp
// 主模板:递归计算 N * Factorial<N-1>::value
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
// 特化:终止递归
template <>
struct Factorial<0> {
static const int value = 1;
};
上述代码中,Factorial<5>::value 会在编译期被展开为 5 * 4 * 3 * 2 * 1,最终变成一个编译期常量 120,没有任何运行时开销。
2. 元函数:把类型当作参数和返回值
TMP 中,我们把处理类型的模板称为元函数。例如,一个"取出常量类型"的元函数:
cpp
template <typename T>
struct AddConst {
using type = const T;
};
// 使用:AddConst<int>::type 即为 const int
这看似简单,但结合递归和特化,就能实现复杂的类型计算。
3. 类型列表:编译期的"链表"
很多 TMP 技巧基于类型列表。我们定义:
cpp
struct NullType {}; // 列表结束标志
template <typename H, typename T>
struct TypeList {
using Head = H; // 当前元素类型
using Tail = T; // 剩余列表
};
借助递归特化,可以计算列表长度、查找元素等------全部在编译期完成。
实战示例:完整的可运行代码
下面给出一个包含编译期阶乘 与类型列表长度计算的完整程序。你可以直接编译运行(C++11及以上即可)。
```cpp
include
include // 仅用于最后类型比对演示
//