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

Sha*_*our 11 c++ gcc language-lawyer constant-expression c++11

请参阅更新以获得更好的问题示例.原始代码有各种各样的问题,使图片混乱:

这个问题为什么我可以在constexpr函数中调用非constexpr函数?提出了以下代码

#include <stdio.h>

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

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

我回答的是格式不正确gcc 4.8.2允许它(现场观看).

但是,如果我们使用该-fno-builtin标志gcc生成错误(请参见它):

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

所以它seemsgcc正在考虑的内置版本printf是一个常量表达式.gcc 这里构建的文档但不记录这种情况,其中非constexpr函数的内置可以被认为是常量表达式.

如果确实如此:

  • 是否允许编译器执行此操作?
  • 如果他们被允许,他们不必记录它是否符合要求?
  • 这可以被视为一个扩展,如果是这样的话,似乎需要一个警告,因为C++草案标准部分1.4 实现合规性8段说(强调我的):

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

更新

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

#include <cmath>
#include <cstdio>

constexpr double f()
{
    return std::pow( 2.0, 2.0 ) ;
}

int main()
{
    constexpr double x = f() ;

    printf( "%f\n", x ) ;
}
Run Code Online (Sandbox Code Playgroud)

编译和构建时没有任何警告或错误(请参见实时),但添加-fno-builtin会使其生成错误(请参见实时).注意:为什么数学函数不是c ++ 11中的constexpr:

error: call to non-constexpr function 'double pow(double, double)'
     return std::pow( 2.0, 2.0 ) ;
                               ^
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 6

是的,gcc正在考虑将一些内置函数作为constexpr,即使标准没有明确标记它们.我们可以发现,特别是涉及到发现数学函数的讨论cmathgcc错误报告[C++ 0x中]的sinh VS ASINH VS constexpr其中说:

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

这是指2013年LWG问题,其最初提议的决议是将以下内容添加到17.6.5.6 [constexpr.functions]部分(强调我的未来):

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

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

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

所以这是(在C++ 14中)一个显式不符合的扩展,据我所知,这在C++ 11中是不符合的,因为它改变了可观察的行为,因此不允许通过as-if规则.

Jonathan Wakely指出了一个libstdc++邮件列表讨论:PR libstdc ++/49813重新访问:constexpr on functions(和builtins) ,由于上面列出的问题,讨论了重新打开上面提到的错误报告:

我相信我们应该根据LWG 2013的实际解决方案重新打开这个bug(禁止添加constexpr).

FE不应该在严格一致性模式下将builtins视为constexpr.

我们应该完全从<cmath>中删除_GLIBCXX_CONSTEXPR,或者使其成为__STRICT_ANSI__的条件.


Cas*_*sey 4

GCC 不认为f()常量表达式。查看您链接的第一个示例程序的诊断:

main.cpp:在函数“int main()”中:
main.cpp:10:19: 警告:ISO C++ 禁止可变长度数组 'a' [-Wvla]
         字符a[f()];
                   ^

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

如果将程序更改为强制转换f()为常量表达式:

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

GCC 确实报告了一个错误

main.cpp:在函数“int main()”中:
main.cpp:10:32:在 'f()' 的 constexpr 扩展中
main.cpp:5:41: 错误:'printf(((const char*)"副作用!\012"))' 不是常量表达式
         return printf("副作用!\n");
                                         ^