使用哪种模板在阶乘中更好?

5

从维基百科上,我看到了一个使用通用编程计算阶乘的示例代码:

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

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

我这边写的代码如下:

template <typename T>
T factorial(T n)
{ 
  T x;

  if (n == 1)
    return 1;

  x = n * factorial(n-1);

  return x;
}

我在Stackoverflow上读到枚举是通用编程中使用的内容,但没有找到相关理由。

那么为什么使用枚举更好?如果第二段代码存在陷阱怎么办?


2
第一个在编译时计算,第二个在运行时计算。 - ChrisMM
@ChrisMM:抱歉问这个问题,但我该如何区分代码片段是在运行时还是编译时计算的。我认为两者都是模板编译时计算的。 - Blood-HaZaRd
这两个代码示例解决不同的问题。第一个示例不能轻松地与用户提供的输入一起使用,而第二个则完全无法在编译时使用。 - François Andrieux
2
@Blood-HaZaRd 在第二个例子中,T 在编译时被解析,但函数本身依赖于 n,这是一个运行时值。第一个例子在编译时计算,因为该值是模板参数,必须在编译时计算。 - François Andrieux
2
仅仅因为一些代码是函数模板,并不意味着它可以或将在编译时完全评估。这只意味着您可以使用编译时信息(您选择的 T)创建不同种类的该函数。 - Lightness Races in Orbit
1个回答

8
第一个是在constexpr函数不存在时所需的。当constexpr没有存在时,枚举是存储在编译时可用的唯一方法。如今,您可以使用 static constexpr 代替枚举来实现相同的基于模板的计算。此外,第一个仅适用于 int 类型而不是通用类型。
第二个是通过模板进行通用类型的,但只在运行时执行。
当然,模板在编译时实例化,但默认情况下实例化的代码仅在运行时执行。
使用constexpr函数,您可以编写同样的代码以供运行时和编译时使用:
template <typename T>
constexpr T factorial(T n)
{ 
  T x{};

  if (n == 1)
    return 1;

  x = n * factorial(n-1);

  return x;
}

int main() {
    int compiletime[factorial(2)];

    int n;
    std::cin >> n;
    int runtime = factorial(n);
}

@LightnessRacesBY-SA3.0:因此,使用枚举模拟了“constexpr”的常量性! - Blood-HaZaRd
@Blood-HaZaRd 确实! - Lightness Races in Orbit
感谢你们提供宝贵的答案和评论。 - Blood-HaZaRd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接