Byz*_*ian 11 c++ evaluation compile-time constexpr c++11
几天前,我询问编译器决定是否在编译期间计算constexpr函数.
事实证明,只有在编译时才会评估constexpr,如果所有参数都是常量表达式,并且您指定给它的变量也是常量表达式.
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
return (expo != 0 )? base * POW(base, expo -1) : 1;
}
template<typename T>
void foobar(T val)
{
std::cout << val << std::endl;
}
int main(int argc, char** argv)
{
foobar(POW((unsigned long long)2, 63));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我被告知是真的,这个代码示例是非常不实际的,因为foobar不接受constexpr(由于某种原因你不能使用consexpr作为参数),POW在运行时被评估,即使它可能是可能的在编译期间计算它.强制编译时评估的明显解决方案是:
auto expr = POW((unsigned long long)2, 63);
foobar(expr);
Run Code Online (Sandbox Code Playgroud)
然而,这迫使我使用额外的代码行,每次我想确保在编译时评估constexpr时都不需要这样做.为了使这更方便一点,我想出了以下可疑的宏:
#define FORCE_CT_EVAL(func) [](){constexpr auto ___expr = func; return std::move(___expr);}()
foobar(FORCE_CT_EVAL(POW((unsigned long long)2, 63)));
Run Code Online (Sandbox Code Playgroud)
尽管它工作得很好,但我觉得好像有些不对劲.创建匿名lambda会影响性能吗?通过rvalue引用返回实际上是将表达式移动到函数参数吗?std :: move如何影响性能?有没有更好的单线解决方案呢?
只是为了不把它埋在评论中:
#include <type_traits>
#define COMPILATION_EVAL(e) (std::integral_constant<decltype(e), e>::value)
constexpr int f(int i){return i;}
int main()
{
int x = COMPILATION_EVAL(f(0));
}
Run Code Online (Sandbox Code Playgroud)
这种方法的一个警告是,constexpr函数可以接受浮点并分配给constexpr浮点变量,但不能将浮点类型用作非类型模板参数。此外,其他类型的文字也有相同的限制。
你的 lambda 会为此工作,但我想你需要一个默认捕获来在非constexpr内容传递给函数时获得有意义的错误消息。这个结局std::move可有可无。
呃,你的 lambda 方法对我不起作用,我刚刚意识到,它甚至可以工作,lambda 不是一个constexpr函数。它也不应该为你工作。
似乎真的没有办法解决它,只能constexpr在本地范围内初始化一个变量。
哦,好吧,我的错,lambda 的目的只是评估。所以它正在为此工作。相反,它的结果是无法跟随另一个编译时间评估。
在 C++17 上,现在可以在constexprcontexts 中使用 lambdas,因此删除了 EDIT2/EDIT3 中提到的限制!所以 lambda 解决方案是正确的。有关更多信息,请参阅此评论。
| 归档时间: |
|
| 查看次数: |
2084 次 |
| 最近记录: |