constexpr vs编译时数学函数的模板?

时间:2012-09-02 04:26:13

标签: c++ templates c++11 metaprogramming constexpr

我对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:修改代码以包含模板专业化

2 个答案:

答案 0 :(得分:8)

我可能不应该在最近回答模板元编程问题。但是,我走了。

首先,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!

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

显然这很好,因为对于许多数学函数,常数传播可以为您提供简单(使用)的过早优化。

它们的主要用途,除了相当深奥的东西(比如使我能够更容易地编写编译时字节码解释器),就是能够创建可以被调用和使用的“函数”或类。在编译时和运行时。

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

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

2可以在运行时调用,而其他只是编译时。那太好了。

还有更多内容。维基百科为您提供了“constexpr允许此项”的基本摘要,但模板元编程可能很复杂。 Constexpr使部分内容变得更加容易。我希望我有一个明确的例子,除了说,从数组中读取。

一个好的数学例子,我想,如果你想实现一个用户定义的复数类。使用模板元编程而没有constexpr进行编码会更复杂一个数量级。

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

庵。好的,这就是现在。我太过于过分而无法说出更多。我希望我能提供帮助,如果我没有,请随时向我投票,我会删除它。

答案 1 :(得分:1)

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

==0编辑专业化后添加。现在,所有函数都适用于编译时或运行时x。 1st将始终返回非constexpr值。如果xN是constexpr,则第2和第3将返回constexpr。如果N不是constexpr,则需要第二次工作,其他需要constexpr N(因此,第二和第三不等同)。

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