在G ++中,在某些条件下,各种内置数学函数都是constexpr。例如,以下编译:
static constexpr double A = __builtin_sqrt(16.0);
static constexpr double B = __builtin_pow(A, 2.0);
它们并不总是constexpr,它取决于论点。例如,__builtin_sqrt(NAN)
在用作常量表达式时会导致编译错误。
但是我遇到了一个奇怪的案例,在我看来它应该是constexpr,但事实并非如此:
static constexpr double value () { return 1.23; }
static constexpr double result = __builtin_round(__builtin_sqrt(value()));
这会产生:
a.cpp:2:73: error: ‘__builtin_round(1.1090536506409416e+0)’ is not a constant expression
static constexpr double result = __builtin_round(__builtin_sqrt(value()));
^
我尝试过以上代码的变体,我发现:
__builtin_round
在问题中有一些特殊的作用。用其他内置数学函数替换它,例如sqrt
或pow
可以解决错误。因此__builtin_round
似乎缺乏constexpr支持。但是... value()
被文字1.23
取代,那么也会删除错误。__builtin_sqrt
,仅保留__builtin_round(value())
,也会删除错误。我想知道为什么round
以这种方式表现,以及是否有任何解决方法。
注意即可。我知道内置的数学函数及其constexpr-ness是非标准的编译器特有的功能。请不要告诉我如何不使用它,或者我不应该如何尝试编译时间数学。在我的情况下,使用constexpr数学是一个重要的特性,我可以依赖G ++。
答案 0 :(得分:3)
我知道另一种解决方法。
有:使用辅助函数pass_through
template<typename T>
constexpr T&& pass_through (T&& t) { return static_cast<T&&>(t); }
像这样使用它:
static constexpr double value () { return 1.23; }
static constexpr double result = __builtin_round(pass_through(__builtin_sqrt(value())));
此代码在G ++中编译时没有错误。
我也同意,认为这个问题应该向海湾合作委员会报告。
答案 1 :(得分:2)
我只能回答你的部分问题,即是否有解决方法。
有:使用助手constexpr
变量。
虽然__builtin_round(__builtin_sqrt(value()))
作为常量表达式被拒绝,但{0}被接受,之后helper = value()
也是如此。或者,result = __builtin_round(__builtin_sqrt(helper))
然后helper = __builtin_sqrt(value())
。
这种不一致表明GCC显然能够在编译时评估表达式,并愿意将其视为result = __builtin_round(helper)
。虽然它可能在标准中找不到支持,但可能值得将此报告为GCC错误跟踪器的增强请求。
至于实际原因,我会猜测 GCC首先执行简单常量折叠,然后检查constexpr
是否需要额外的常量折叠,如果是,则检查表达式是否匹配constexpr
要求,如果是,则计算结果。检查将失败,因为表达式在技术上是无效的,但额外的辅助变量将改进简单的常量折叠,以便在检查有效性时,无效的内置函数不再存在。但就像我说的那样,这是猜测。
答案 2 :(得分:1)
这似乎适用于g ++ 4.8.2:
static constexpr double value () { return 1.23; }
static constexpr double root(double x) { return sqrt(x);}
static constexpr double result = roundl(root(value()));
有趣的是,如果我将roundl
替换为round
,编译器会抱怨:
error: ‘round(1.1090536506409416e+0)’ is not a constant expression
这也有效:
static constexpr double value () { return 1.23; }
static constexpr double roundroot(double x) { return roundl(sqrt(x));}
static constexpr double result = roundroot(value());
但同样,只有roundl
而不是round
。当使用相应的__builtin_
版本(这些版本只是换行)时,所有这些都是正确的。
我现在正在下载gcc
来源以查看但是没有回答&#34;为什么&#34;爱好。