constexpr与编译时数学函数的模板

constexpr vs template for compile-time maths functions?

本文关键字:函数 编译 constexpr      更新时间:2023-10-16

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

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

首先,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中的一个漏洞,并有助于编译器进行优化。

那么你的三个中哪一个是"最好的"呢?

2可以在运行时调用,而其他的仅在编译时调用。真是太甜蜜了。

维基百科给出了"constexpr允许这样做"的基本总结,但模板元编程可能很复杂。Constexpr使它的某些部分变得容易多了。我希望我能给你一个明确的例子,而不是说,从数组中读取。

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

那么什么时候不应该使用constexpr呢?老实说,constexpr基本上是"除MORE const之外的const"。你通常可以在任何使用const的地方使用它,但需要注意一些问题,比如在运行时调用函数时,如果函数的输入不是const,函数将如何执行非const。

嗯。好了,现在就说到这里。我太累了,说不出更多话来。我希望我能帮上忙,如果我没有帮上忙的话,可以投我一票,我会删除这个。

第1个和第3个不正确。编译器将在计算(N>0) ?之前尝试实例化tpow<N-1>,您将获得无限的模板递归。你需要N==1(或==0)的专业化才能让它发挥作用。第二个将用于在编译时和运行时已知的x

在您的==0编辑专业化后添加。现在,所有函数都将在编译时或运行时x工作。1st将始终返回非常常量表达式值。如果xN是constexpr,则2nd和3rd将返回constexpr。如果N不是constexpr,则第二个也工作,其他需要constexpr N(因此,第二个和第三个不相等)。

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