constexpr与编译时数学函数的模板
constexpr vs template for compile-time maths functions?
我对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将始终返回非常常量表达式值。如果x
和N
是constexpr,则2nd和3rd将返回constexpr。如果N
不是constexpr,则第二个也工作,其他需要constexpr N
(因此,第二个和第三个不相等)。
constexpr用于两种情况。当您编写int N=10;
时,N的值在编译时是已知的,但它不是constexpr,不能用作模板参数。关键字constexpr显式地告诉编译器N
用作编译时值是安全的。第二个用途是作为constexpr函数。它们使用C++的子集来有条件地生成constexpr值,并可以极大地简化等效的模板函数。constexpr函数的一个缺点是,您并没有保证的编译时求值——编译器可以选择在运行时进行求值。有了模板化的实现,就可以保证在编译时进行评估。
- 跨模板化函数编译的静态变量
- 无法使用 LoadObject() 函数编译 UE4 Actor。
- 为什么在使用转换构造函数编译代码时需要 const 复制构造函数?
- 函数编译,即使它不接受整数
- 使用C 模板函数编译时间递归
- 安卓 JNI - 'raw'函数编译失败
- C++就地析构函数编译警告
- 对 TR1 使用 boost 时提升数学特殊函数编译错误
- 显式复制构造函数编译错误
- 使用SSE内部函数编译一个简单的c++程序
- 函数编译时错误
- 模板函数编译错误
- C++:使用类型名作为基的模板类调用函数编译时错误
- 将 MATLAB 函数编译成可以在 linux 终端上运行的东西,w.out MATLAB
- boost::绑定不要使用成员模板函数编译
- C++函数编译错误
- 加速模板函数编译
- 如何在C++中使用辅助函数编译以下flex文件
- 如何让g++使用move构造函数编译c++11代码
- 同时将一组函数编译为.LIB和.DLL