在之前的文章里讲到,C++ 的模板可以用来做编译期计算。实际上 C++ 的模板可以当作一种程序语言来写,它是图灵完备的,这篇文章就来专门聊它。
首先必须要说,在日常开发中,需要用模板来做编译期计算的场景并不多。当需要用模板做这类事情时,需要慎重考虑是不是在过早优化,是不是有替代方案,例如 constexpr
。滥用模板的这类技巧一定会导致项目难以维护和更长的编译时间。
我们来看一个例子。假设我们要写判断一个整数是否为素数的程序,我们写一个非常简单的版本:
bool is_prime(int a) {
if (a < 2) return false;
for (int i = 2; i < a; ++i) {
if (a % i == 0) return false;
}
return true;
}
接下来考虑如何使用模板实现它。我们说让模板完成计算,实际上就是让编译器在编译期间对模板求值。在这个过程里,模板可以在编译期递归的展开。和类型萃取的技巧类似,最终我们期待一个这样的模板表达式is_prime<42>::value
,其中 42
是一个非类型模板参数(non-type parameter)。
我们知道,一般计算逻辑的控制流里都是有“条件判断”和“循环”的,用模板如何表达“条件判断”和“循环”呢?你应该已经想到了——用模板的匹配规则(类型的特化/偏特化 和 SFINAE)表达“条件判断”,用模板的递归展开表达“循环”。在用模板写这个函数前,我们先把原来的函数写成递归形式:
bool has_factor(int a, int i) {
if (i ==