9

我对 C++2011 的新关键字 constexpr 感到很困惑。当我编写编译时函数(尤其是数学函数)时,我想知道在哪里使用 constexpr 以及在哪里使用模板元编程。例如,如果我们采用整数 pow 函数:

// 1 : 
template <int N> inline double tpow(double x)
{
    return x*tpow<N-1>(x);
}
template <> inline double tpow<0>(double x)
{
    return 1.0;
}

// 2 :
constexpr double cpow(double x, int N)
{
    return (N>0) ? (x*cpow(x, N-1)) : (1.0);
}

// 3 :
template <int N> constexpr double tcpow(double x)
{
    return x*tcpow<N-1>(x);
}
template <> constexpr double tcpow<0>(double x)
{
    return 1.0;
}

第二个和第三个功能是等效的吗?什么是最好的解决方案?它是否产生相同的结果:

  • 如果 x 在编译时已知
  • 如果 x 在编译时未知

何时使用 constexpr 以及何时使用模板元编程?

编辑 1:修改代码以包括模板的专业化

4

2 回答 2

9

我可能不应该这么晚才回答模板元编程问题。但是,我来了。

首先,constexpr 没有在 Visual Studio 2012 中实现。如果你想为 windows 开发,那就别管它了。我知道,这很糟糕,我讨厌微软不包括它。

除此之外,您可以将很多东西声明为常量,但就“您可以在编译时使用它们”而言,它们并不是真正的“常量”。例如:

const int foo[5] = { 2, 5, 1, 9, 4 };
const int bar = foo[foo[2]]; // Fail!

你会认为你可以在编译时从中读取,对吧?没有。但是,如果您将其设为 constexpr,则可以。

constexpr int foo[5] = { 2, 5, 1, 9, 4 };
constexpr int bar = foo[foo[2]]; // Woohoo!

Consexpr 非常适合“恒定传播”优化。这意味着如果您有一个变量 X,它是在编译时根据某些条件(可能是元编程)声明的,如果它是一个 constexpr,那么编译器知道它可以在进行优化时“安全地”使用它,例如,删除像 a = (X * y); 这样的指令 并将它们替换为 a = 0; 如果 X 评估为 0(并且满足其他条件)。

显然这很好,因为对于许多数学函数,常量传播可以给你一个容易(使用)的过早优化。

它们的主要用途,而不是相当深奥的东西(例如使我能够更容易地编写编译时字节码解释器),是能够制作可以在编译时调用和使用的“函数”或类-时间和运行时。

基本上,它们只是填补了 C++03 中的一个漏洞,并帮助编译器进行优化。

那么你的三个中哪个是“最好的”?

2 可以在运行时调用,而其他的只能在编译时调用。这很甜蜜。

还有一点。Wikipedia 为您提供了“constexpr 允许这样做”的非常基本的摘要,但模板元编程可能很复杂。Consexpr 使它的某些部分变得容易得多。我希望我有一个明确的例子给你,而不是说从数组中读取。

我想一个很好的数学例子是如果你想实现一个用户定义的复数类。仅使用模板元编程而没有 constexpr 的代码将复杂一个数量级。

那么什么时候不应该使用 constexpr?老实说,constexpr 基本上是“除 MORE CONST 之外的 const”。您通常可以在使用 const 的任何地方使用它,但有一些注意事项,例如在运行时调用时,如果函数的输入不是 const,函数将如何表现非 const。

嗯。好的,这就是现在的全部。我太累了,不能多说。我希望我对您有所帮助,如果我不是,请随时对我投反对票,我将删除此内容。

于 2012-09-02T05:37:40.570 回答
1

第 1 和第 3 是不正确的。tpow<N-1>编译器将在评估之前尝试实例化(N>0) ?,您将获得无限的模板递归。您需要对N==1(或==0)进行专业化才能使其工作。2nd 将x在编译时和运行时工作。

在您的专业化==0编辑后添加。现在所有功能都将适用于编译时或运行时x。1st 将始终返回非 constexpr 值。x如果和是 constexpr,则 2nd 和 3rd 将返回Nconstexpr。N如果不是 constexpr,则第二个甚至可以工作,其他需要 constexpr N(因此,第二个和第三个不等价)。

constexpr 用于两种情况。当您编写int N=10;时, N 的值在编译时是已知的,但它不是 constexpr 并且不能用作例如模板参数。关键字 constexpr 明确告诉编译器N可以安全地用作编译时值。第二个用途是作为 constexpr 函数。他们使用 C++ 的子集有条件地生成 constexpr 值,并且可以显着简化等效的模板函数。constexpr 函数的一个缺点是您无法保证编译时评估——编译器可以选择在运行时进行评估。使用模板实现可以保证编译时评估。

于 2012-09-02T05:02:20.433 回答