将非 constexpr 标准库函数视为 constexpr 是否符合编译器扩展?
gcc
在没有警告的情况下编译以下代码:
gcc
compiles the following code without warning:
#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]:
None of the standard library functions used above are constexpr functions, we are allowed to use them where a constant expression is required from both the draft C++11 standard and draft C++14 standard section 7.1.5
[dcl.constexpr]:
[...]如果它是由构造函数调用初始化的,则该调用应为常量表达式 (5.19).否则,或者如果 constexpr 说明符是在引用声明中使用,出现在它的初始化器应该是一个常量表达式.[...]
[...]If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, or if a constexpr specifier is used in a reference declaration, every full expression that appears in its initializer shall be a constant expression.[...]
即使使用 -std=c++14 -pedantic
或 -std=c++11 -pedantic
也不会产生警告(现场观看).使用 -fno-builtin
会产生错误(实时查看) 这表明这些标准库函数的 builtin 版本被视为constexpr
Even when using -std=c++14 -pedantic
or -std=c++11 -pedantic
no warnings are generated (see it live). Using -fno-builtin
produces errors (see it live) which indicates that the builtin version of these standard library functions are being treated as if they where constexpr
虽然 clang
不允许使用我尝试过的任何标志组合的代码.
While clang
does not allow the code with any combination of flags I have tried.
所以这是一个 gcc
扩展,至少将一些内置函数视为 constexpr 函数,即使标准没有明确要求它们.我本来希望至少在严格符合模式下收到警告,这是符合标准的扩展吗?
So this is a gcc
extension to treat at least some builtin functions as if they were constexpr functions even though the standard does not explicitly require them to be. I would have expected to at least receive a warning in strict conformance mode, is this a conforming extension?
推荐答案
TL;DR
在 C++14 中这是明确不允许的,尽管在 2011
中似乎这种情况是明确允许的.目前尚不清楚 C++11 这是否属于 as-if 规则,我不相信它会改变可观察到的行为,但我在下面提到的问题中没有澄清这一点.
In C++14 this is explicitly not allowed, although in 2011
it appeared like this case would be explicitly allowed. It is unclear if for C++11 this fell under the as-if rule, I don't believe it does since it alters observable behavior but that point was not clarified in the issue I reference below.
详情
这个问题的答案随着LWG 问题 2013 其开头为:
The answer to this question has shifted with the evolving status of LWG issue 2013 which opens with:
假设一个特定的函数没有被标记为 constexpr标准,但在某些特定的实现中,有可能在 constexpr 约束内编写它.如果实施者标记像 constexpr 这样的函数,是违反标准或它是符合标准的扩展吗?
Suppose that a particular function is not tagged as constexpr in the standard, but that, in some particular implementation, it is possible to write it within the constexpr constraints. If an implementer tags such a function as constexpr, is that a violation of the standard or is it a conforming extension?
在 C++11 中,不清楚 as-if 规则是否允许这样做,但原始提案一旦被接受就会明确允许它,我们可以在下面的 gcc 错误报告中看到我参考,这是gcc团队做出的假设.
In C++11 it was unclear if the as-if rule permitted this but the orignal proposal would have explicitly allowed it once it was accepted and we can see below in the gcc bug report I reference, this was the assumption made by the gcc team.
在 2012 年达成的共识发生了变化,提案发生了变化,在 C++14 中,这是一个不符合标准的扩展.这反映在 C++14 标准部分草案 17.6.5.6
[constexpr.functions] 中,它说:
The consensus to allow this shifted in 2012 and the proposal changed and in C++14 this is a non-conforming extension. This is reflected in the draft C++14 standard section 17.6.5.6
[constexpr.functions] which says:
[...]一个实现不应声明任何标准库函数签名为 constexpr,但明确表示的除外需要.[..]
[...]An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.[..]
虽然对这一点的严格阅读似乎为隐式地将内置函数视为 constexpr 留下了一些回旋余地,但我们可以从问题中的以下引用中看出,其目的是为了防止实现中的分歧,因为相同的代码可以使用SFINAE(强调我的)时产生不同的行为:
and although a strict reading of this seems to leave some wiggle room for treating a builtin implicitly as if it were a constexpr we can see from the following quote in the issue that the intention was to prevent divergence in implementations since identical code could produce different behavior when using SFINAE (emphasis mine):
在提交给全体委员会投票时表达了一些担忧WP 状态,该问题已在没有足够的情况下得到解决考虑 不同库实现的后果,如用户可以使用 SFINAE 来观察与其他方式不同的行为相同的代码.
Some concern expressed when presented to full committee for the vote to WP status that this issue had been resolved without sufficient thought of the consequences for diverging library implementations, as users may use SFINAE to observe different behavior from otherwise identical code.
我们可以从 gcc 的 bug 报告中看到 [C++0x] sinh vsasinh vs constexpr 团队依赖于早先提出的 LWG 2013 决议 表示:
We can see from the gcc bug report [C++0x] sinh vs asinh vs constexpr that the team relied on the earlier proposed resolution of LWG 2013 which says:
[...]此外,一个实现可以声明任何函数为constexpr 如果该函数的定义满足必要的约束[...]
[...]Additionally, an implementation may declare any function to be constexpr if that function's definition satisfies the necessary constraints[...]
在决定是否在严格一致性模式下允许对数学函数进行此更改时.
when deciding whether this change for the math functions was allowed in strict conformance mode.
据我所知,如果我们在严格合规模式下收到警告,即使用 -std=c++11 -pedantic
或者在这种模式下禁用它,这将变得合规.
As far as I can tell this would become conforming if this we received a warning in strict conformance mode i.e. using -std=c++11 -pedantic
or if it was disabled in this mode.
请注意,我在错误报告中添加了一条评论,说明自最初解决此问题以来,分辨率已更改.
Note, I added a comment to the bug report explaining that the resolution changed since this issue was originally addressed.
Jonathan Wakely 指出 在另一个问题中,最近的讨论和似乎将重新打开 gcc 错误报告以解决此一致性问题.
Jonathan Wakely pointed out in another question a more recent discussion and it seems likely the gcc bug report will be reopened to address this conformance issue.
内在函数呢
编译器内在函数 不在标准范围内,据我所知他们应该不受此规则的约束,因此使用:
Compiler intrinsics are not covered by the standard and so as far as I can tell they should be exempt from this rule, so using:
static constexpr double a = __builtin_cos(3.);
应该允许.这个问题出现在错误报告中,Daniel Krügler 的意见是:
should be allowed. This question came up in the bug report and opinion of Daniel Krügler was:
[...] 库函数和其他内在函数可能被认为是例外,因为它们不需要被解释"正常的语言规则.
[...]Library functions and other intrinsics can probably be considered as exceptions, because they are not required to be "explainable" by normal language rules.
相关文章