将constexpr标准库函数视为constexpr是否符合编译器扩展?

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() { } 

上面使用的标准库函数都不是constexpr函数 ,我们可以在C ++ 11标准 草案和C ++ 14标准草案 7.1.5 [dcl.constexpr] 草案中要求使用常量expression式的地方使用它们。

[…]如果它是由构造函数调用初始化的,那么这个调用应该是一个常量expression式(5.19)。 否则,或者如果在引用声明中使用了constexpr说明符,则在其初始化符中出现的每个完整expression式应该是一个常量expression式。

即使使用-std=c++14 -pedantic-std=c++11 -pedantic不会生成警告( 请参阅实况 )。 使用-fno-builtin会产生错误( 现场看到 ),这表明这些标准库函数的内置版本正在被视为如何处理constexpr

虽然clang不允许任何组合的代码我已经尝试过。

所以这是一个gcc扩展,至less将一些内置函数看作是constexpr函数,即使标准没有明确地要求它们。 我希望至less能够以严格的一致性模式接受警告,这是否符合要求?

TL; DR

在C ++ 14中,这是明确的不允许的,尽pipe在2011看起来像这种情况下将被明确允许。 目前还不清楚C ++ 11 是否属于as-if规则 ,我不相信这是因为它改变了可观察到的行为,但是这个问题在我下面提到的问题中没有被阐明。

细节

这个问题的答案已经随着2013年LWG问题的演变而改变,

假设一个特定的函数在标准中没有被标记为constexpr,但是在某些特定的实现中,可以在constexpr约束条件下编写它。 如果实施者标签为constexpr等function,是违反标准还是符合规定?

在C ++ 11中,如果as-if规则允许这样做,还不清楚,但是原始提案一旦被接受,我们可以明确地允许它,我们可以在下面的gcc错误报告中看到,这是gcc的假设球队。

在2012年允许这个转变的共识,改变了提案,而在C ++ 14中,这是一个不合适的扩展。 这反映在C ++ 14标准第17.6.5.6[constexpr.functions]中:

[…]一个实现不应该声明任何标准库函数签名为constexpr,除了明确要求的那些。[…]

尽pipe严格的阅读似乎留下了一些隐含的处理内build的空间,好像它是一个constexpr,我们可以从这个问题的下面的引用中看出,其目的是为了防止实现中的差异,因为相同的代码会产生不同的行为当使用SFINAE强调我的 ):

当提交给WP完整委员会投票时,有人担心这个问题已经得到解决,因为用户可能使用SFINAE来观察与其他代码不同的行为

我们可以从海湾合作委员会的错误报告[C ++ 0x] sinh vs asinh vs constexpr看出,该团队依赖于早先提出的LWG 2013的决议,其中说:

[…]另外,如果函数的定义满足必要的约束条件,则实现可以声明任何函数是constexpr […]

当决定这个math函数的改变是否被允许在严格的一致性模式下。

据我所知,如果我们收到一个严格的一致性模式的警告,即使用-std=c++11 -pedantic或者在这种模式下被禁用,这将会变得一致。

请注意,我在错误报告中添加了一条评论,说明自从这个问题最初提出以来,决议发生了变化。

Jonathan Wakely在另一个问题中指出了最近的一次讨论 ,似乎gcc bug报告将重新打开,以解决这个一致性问题。

什么是内在的

编译器内在函数不在标准范围内,所以据我所知,他们应该被免除这个规则,所以使用:

 static constexpr double a = __builtin_cos(3.); 

应该被允许。 这个问题出现在bug报告中,DanielKrügler的观点是:

图书馆function和其他内在因素可能被认为是例外情况,因为它们不需要通过正常的语言规则来“解释”。