它是一个符合标准的编译器扩展,将非constexpr标准库函数视为constexpr吗?

Sha*_*our 38 c++ gcc language-lawyer c++11 c++14

gcc 在没有警告的情况下编译以下代码:

#include <cmath>

struct foo {
  static constexpr double a = std::cos(3.);
  static constexpr double c = std::exp(3.);
  static constexpr double d = std::log(3.);
  static constexpr double e1 = std::asin(1.);
  static constexpr double h = std::sqrt(.1);
  static constexpr double p = std::pow(1.3,-0.75);
};

int main()
{
}
Run Code Online (Sandbox Code Playgroud)

的上面使用的标准库函数都不是constexpr功能,我们允许使用它们,其中一个常量表达式从两个需要草案C++ 11标准草案C++ 14标准7.1.5 [dcl.constexpr] :

[...]如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.19).否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式.[...]

即使使用-std=c++14 -pedantic-std=c++11 -pedantic没有生成警告(请参见实时).使用-fno-builtin产生错误(参见实时),表明这些标准库函数的内置版本被视为constexpr

虽然clang不允许使用任何标志组合的代码我尝试过.

所以这是一个gcc扩展来处理至少一些内置函数,好像它们是constexpr函数,即使标准没有明确要求它们.我本来期望至少在严格的一致性模式下收到警告,这是一个符合标准的扩展吗?

Sha*_*our 41

TL; DR

在C++ 14中,这显然是不允许的,尽管在2011这种情况下似乎是明确允许的.目前还不清楚C++ 11 是否属于as-if规则,我不相信,因为它改变了可观察到的行为,但我在下面引用的问题中并没有澄清这一点.

细节

这个问题的答案随着2013年LWG问题的演变而变化,该问题开始于:

假设特定函数未在标准中标记为constexpr,但在某些特定实现中,可以在constexpr约束内编写它.如果实施者标记constexpr这样的功能,是违反标准还是符合标准的扩展?

在C++ 11中,不清楚as-if规则是否允许这样做,但是orignal提议一旦被接受就明确允许它,我们可以在下面的gcc bug报告中看到我引用,这是gcc做出的假设球队.

允许这种转变的共识在2012年发生了变化并且提案发生了变化,而在C++ 14中,这是一个不合规的扩展.这反映在草案C++ 14标准部分17.6.5.6 [constexpr.functions]中,该部分说:

[...]实现不得将任何标准库函数签名声明为constexpr,除非明确要求它.[...]

虽然严格阅读这个内容似乎留下了一些回避处理内置因素的余地,好像它是一个constexpr我们可以从问题中的以下引用中看出,目的是防止实现中的分歧,因为相同的代码可能会产生不同的行为使用SFINAE时(强调我的):

当向完全委员会提交对WP状态的投票时表达了一些担忧,即在没有充分考虑图书馆实施不同的后果的情况下解决了这个问题,因为用户可能会使用SFINAE观察其他相同代码的不同行为.

我们可以从gcc bug报告[C++ 0x] sinh vs asinh vs constexpr看到该团队依赖早先提出的LWG 2013决议,其中说:

[...]此外,如果该函数的定义满足必要的约束,则实现可以声明任何函数为constexpr [...]

在确定是否允许在严格一致性模式下对数学函数进行此更改时.

据我所知,如果我们在严格的一致性模式下收到警告,即使用-std=c++11 -pedantic或者在此模式下被禁用,这将符合要求.

请注意,我在错误报告中添加了一条评论,解释说自从此问题最初解决后,解决方案已更改.

Jonathan Wakely 在另一个问题中指出了一个更近期的讨论,似乎可能会重新打开gcc bug报告来解决这个一致性问题.

本质上怎么样?

编译器内在函数不在标准范围内,因此,据我所知,它们应该免于此规则,因此使用:

static constexpr double a = __builtin_cos(3.);
Run Code Online (Sandbox Code Playgroud)

应该被允许.这个问题出现在错误报告中,DanielKrügler的意见是:

[...]库函数和其他内在函数可能被视为异常,因为它们不需要通过常规语言规则"解释".