计算因子

可以使用模板元编程技术在编译时计算因子。

#include <iostream>

template<unsigned int n>
struct factorial
{
    enum
    {
        value = n * factorial<n - 1>::value
    };
};

template<>
struct factorial<0>
{
    enum { value = 1 };
};

int main()
{
    std::cout << factorial<7>::value << std::endl;    // prints "5040"
}

factorial 是一个结构,但在模板元编程中,它被视为模板元函数。按照惯例,模板元函数通过检查特定成员来评估,::type 用于产生类型的元函数,或::value 用于生成值的元函数。

在上面的代码中,我们通过使用我们想要传递的参数实例化模板来评估 factorial 元函数,并使用::value 来获得评估结果。

元函数本身依赖于以较小的值递归地实例化相同的元函数。factorial<0> 专业化代表终止条件。模板元编程具有函数式编程语言的大多数限制,因此递归是主要的循环构造。

由于模板元函数在编译时执行,因此它们的结果可用于需要编译时值的上下文中。例如:

int my_array[factorial<5>::value];

自动数组必须具有编译时定义的大小。元函数的结果是编译时常量,因此可以在这里使用。

限制 :大多数编译器不允许递归深度超出限制。例如,g++编译器默认情况下将递归限制为 256 级。对于 g++,程序员可以使用 -ftemplate-depth-X 选项设置递归深度。

Version >= C++ 11

从 C++ 11 开始,std::integral_constant 模板可以用于这种模板计算:

#include <iostream>
#include <type_traits>

template<long long n>
struct factorial :
  std::integral_constant<long long, n * factorial<n - 1>::value> {};

template<>
struct factorial<0> :
  std::integral_constant<long long, 1> {};

int main()
{
    std::cout << factorial<7>::value << std::endl;    // prints "5040"
}

此外,constexpr 功能成为更清洁的选择。

#include <iostream>

constexpr long long factorial(long long n)
{
  return (n == 0) ? 1 : n * factorial(n - 1);
}

int main()
{
  char test[factorial(3)];
  std::cout << factorial(7) << '\n';
}

factorial() 的主体被写为单个语句,因为在 C++ 11 中,constexpr 函数只能使用非常有限的语言子集。

Version >= C++ 14

从 C++ 14 开始,对 constexpr 函数的许多限制已被删除,现在可以更方便地编写它们:

constexpr long long factorial(long long n)
{
  if (n == 0)
    return 1;
  else
    return n * factorial(n - 1);
}

甚至:

constexpr long long factorial(int n)
{
  long long result = 1;
  for (int i = 1; i <= n; ++i) {
    result *= i;
  }
  return result;
}

Version >= C++ 17

从 c ++ 17 开始,可以使用 fold 表达式来计算阶乘:

#include <iostream>
#include <utility>

template <class T, T N, class I = std::make_integer_sequence<T, N>>
struct factorial;

template <class T, T N, T... Is>
struct factorial<T,N,std::index_sequence<T, Is...>> {
   static constexpr T value = (static_cast<T>(1) * ... * (Is + 1));
};

int main() {
   std::cout << factorial<int, 5>::value << std::endl;
}