__builtin_round不是常量表达式

时间:2014-05-03 17:39:32

标签: c++ floating-point g++ constexpr built-in

在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在问题中有一些特殊的作用。用其他内置数学函数替换它,例如sqrtpow可以解决错误。因此__builtin_round似乎缺乏constexpr支持。但是...
  • 如果value()被文字1.23取代,那么也会删除错误。
  • 删除__builtin_sqrt,仅保留__builtin_round(value()),也会删除错误。

我想知道为什么round以这种方式表现,以及是否有任何解决方法。

注意即可。我知道内置的数学函数及其constexpr-ness是非标准的编译器特有的功能。请不要告诉我如何不使用它,或者我不应该如何尝试编译时间数学。在我的情况下,使用constexpr数学是一个重要的特性,我可以依赖G ++。

3 个答案:

答案 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;爱好。