gcc是否将非常量表达式函数的内置函数视为常量表达式

时间:2014-03-04 20:34:05

标签: c++ gcc c++11 language-lawyer constant-expression

请参阅更新以获得更好的问题示例。原始代码有各种各样的问题混淆了图片

此问题Why can I call a non-constexpr function inside a constexpr function?提供了以下代码

#include <stdio.h>

constexpr int f()
{
    return printf("a side effect!\n");
}

int main()
{
    char a[f()];
    printf("%zd\n", sizeof a);
}

我回答的是格式错误的,但gcc 4.8.2允许它( see it live )。

但是,如果我们使用-fno-builtin标记gcc生成错误( see it live ):

error: call to non-constexpr function 'int printf(const char*, ...)'
     return printf("a side effect!\n");
                                     ^

所以seems gcc正在考虑将printf的内置版本作为常量表达式gcc1.4 documents builtins here但未记录此情况,其中非constexpr函数的内置可被视为常量表达式。

如果情况确实如此:

  • 是否允许编译器执行此操作?
  • 如果他们被允许,他们是否必须将其记录为符合要求?
  • 这可以被视为一个扩展,如果是这样的话,似乎需要警告C++ draft standard部分#include <cmath> #include <cstdio> constexpr double f() { return std::pow( 2.0, 2.0 ) ; } int main() { constexpr double x = f() ; printf( "%f\n", x ) ; } 实施合规性 8 说(强调我的):
  

符合要求的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为。 根据本国际标准诊断使用此类扩展的程序需要实施。但是,这样做之后,他们就可以编译和执行这些程序。

更新

正如凯西所指出的那样,原始问题中有一些事情发生,这使得它成为一个糟糕的例子。一个简单的例子是使用std::pow,它不是constexpr函数:

-fno-builtin

编译和构建时没有任何警告或错误( see it live )但添加error: call to non-constexpr function 'double pow(double, double)' return std::pow( 2.0, 2.0 ) ; ^ 会导致生成错误( see it live )。注意:why math functions are not constexpr in C++11

{{1}}

2 个答案:

答案 0 :(得分:6)

是的,gcc正在考虑将某些builtin functions视为 constexpr ,即使标准没有明确标记它们。我们可以在cmath错误报告[C++0x] sinh vs asinh vs constexpr中找到与gcc中的数学函数相关的讨论,其中包含:

  

LWG 2013似乎确实允许GCC将这些功能视为constexpr。   所以,固定为4.7

指的是LWG issue 2013,其原始提议的解决方案是将以下内容添加到17.6.5.6 [constexpr.functions] 部分(强调我的前进 EM>):

  

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

但是在C ++ 11之后,分辨率被颠倒了,最终的分辨率结束为:

  

[...]实现不得声明任何标准库函数   签名为constexpr,除非是明确的签名   必需的。[..]

所以这是目前(在C ++ 14 中)a explicitly non-conforming extension并且据我所知,这在C ++ 11中是不符合的,因为它改变了可观察的行为,因此不允许通过 as-if规则

Jonathan Wakely指出libstdc++邮件列表讨论:PR libstdc++/49813 revisited: constexpr on functions (and builtins)由于上述问题,我们重新讨论了上述错误报告:

  

我相信我们应该根据实际的分辨率重新打开这个错误   LWG 2013(禁止添加constexpr)。

     

富裕不应该将内含者视为严格一致的constexpr   模式。

     

我们应该从&lt; cmath&gt;中删除_GLIBCXX_CONSTEXPR。完全或   以__STRICT_ANSI __。

为条件

答案 1 :(得分:4)

GCC 认为f()是一个常量表达式。查看the first sample program you linked的诊断信息:

main.cpp: In function 'int main()':
main.cpp:10:19: warning: ISO C++ forbids variable length array 'a' [-Wvla]
         char a[f()];
                   ^

编译器认为f()不是常量表达式,程序实际上是使用GCC的扩展,它允许可变长度数组 - 具有非常数大小的数组。

如果您更改程序以强制f()为常量表达式:

int main() {
    constexpr int size = f();
    char a[size];
    printf("%zd\n", sizeof a);
}

GCC does report an error

main.cpp: In function 'int main()':
main.cpp:10:32:   in constexpr expansion of 'f()'
main.cpp:5:41: error: 'printf(((const char*)"a side effect!\012"))' is not a constant expression
         return printf("a side effect!\n");
                                         ^