gcc 是否将非常量表达式函数的内置视为常量表达式
Is gcc considering builtins of non-constant expression functions to be constant expressions
请参阅更新以获取更好的问题示例。原始代码混合了使图片混乱的问题:
这个问题 为什么我可以在 constexpr 函数中调用非 constexpr 函数? 提供了以下代码
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!n");
}
int main()
{
char a[f()];
printf("%zdn", sizeof a);
}
正如我的回答,这是格式不正确的,但gcc 4.8.2
允许它(现场观看)。
但是,如果我们使用-fno-builtin
标志gcc
生成错误(实时查看):
error: call to non-constexpr function 'int printf(const char*, ...)'
return printf("a side effect!n");
^
因此,gcc
seems
将其内置版本的printf
视为常量表达式。gcc
在此处记录内置,但不记录这种情况,其中非constexpr函数的内置可以被视为常量表达式。
如果确实如此:
- 编译器可以这样做吗?
- 如果他们被允许,他们不需要记录它才能符合要求吗?
- 这是否可以被视为扩展,如果是这样,这似乎需要一个警告,因为C++草案标准部分
1.4
执行合规性第8段说(强调我的):
符合标准的实现可以具有扩展(包括附加的库函数),前提是它们不改变任何格式良好的程序的行为。需要实现来诊断使用此类扩展的程序,这些扩展根据本国际标准格式不正确。但是,这样做后,他们可以编译和执行此类程序。
更新
正如凯西指出的那样,原始问题中发生了一些事情,使其成为一个糟糕的例子。一个简单的例子是使用 std::p ow,它不是一个 constexpr 函数:
#include <cmath>
#include <cstdio>
constexpr double f()
{
return std::pow( 2.0, 2.0 ) ;
}
int main()
{
constexpr double x = f() ;
printf( "%fn", x ) ;
}
编译和构建时没有警告或错误(实时查看),但添加-fno-builtin
会生成错误(实时查看)。注意:为什么数学函数在 C++11 中不是 constexpr:
error: call to non-constexpr function 'double pow(double, double)'
return std::pow( 2.0, 2.0 ) ;
^
是的,gcc
正在考虑将一些内置函数视为constexpr,即使标准没有明确标记它们。我们可以在gcc
错误报告 [C++0x] 中找到专门与cmath
中的数学函数相关的讨论 sinh vs asinh vs constexpr 其中说:
LWG 2013似乎确实允许GCC将这些功能视为constexpr。 所以,固定为 4.7
它指的是LWG问题2013,其最初提出的决议是在第17.6.5.6
[constexpr.functions]节中添加以下内容(强调我的):
[...]此外,实现可以将任何函数声明为 constexpr 如果该函数的定义满足必要的 约束[...]
但在C++11之后,决议被推翻,最终决议最终为:
[...]实现不得声明任何标准库函数 签名为 constexpr,但明确签名的签名除外 必填。[..]
所以这目前(在 C++14 中)是一个明确的不合规扩展,据我所知,这在 C++11 中是不合规的,因为它改变了可观察的行为,因此不允许通过as-if 规则。
Jonathan Wakely 指出了一个libstdc++
邮件列表讨论:PR libstdc++/49813 重新审视:constexpr 关于函数(和内置),由于上述问题,重新打开上述错误报告:
我相信我们应该根据实际解决方案重新打开该错误 LWG 2013(禁止添加 constexpr)。
FE 不应将内置函数视为严格一致性的 constexpr 模式。
我们应该从
中完全删除_GLIBCXX_CONSTEXPR或 使其以__STRICT_ANSI__为条件。
GCC 不认为f()
是一个常量表达式。查看您链接的第一个示例程序的诊断程序:
main.cpp:在函数 'int main()' 中: 主.cpp:10:19: 警告:ISO C++禁止可变长度数组 'a' [-WVLA] 字符 A[f()]; ^
编译器不认为f()
是一个常量表达式,程序实际上使用的是GCC的扩展,该扩展允许可变长度数组 - 具有非恒定大小的数组。
如果更改程序以强制f()
为常量表达式:
int main() {
constexpr int size = f();
char a[size];
printf("%zdn", sizeof a);
}
GCC 确实报告了一个错误:
main.cpp:在函数 'int main()' 中: main.cpp:10:32: 在 constexpr 中扩展 'f()' main.cpp:5:41: 错误:"printf(((const char*)"a side effect!\012"))' 不是常量表达式 返回 printf("一个副作用!"); ^
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 使用自动推导的 lambda 参数作为常量表达式
- 生成提升::hana::set 的常量表达式问题
- 为什么不能用常量表达式声明数组?
- 不是 lambda 函数中的常量表达式
- 函数调用在常量表达式中必须具有常量值
- 错误:constexpr 变量'struct2Var'必须由常量表达式初始化
- 关于在需要常量表达式的上下文中使用的glvalue常量表达式的问题
- 生成 constexpr 字符串表,不能产生常量表达式
- 整体模板参数。错误:在常量表达式中使用'this'
- 如何在满足常量表达式的同时将整数传递给指针,传递给 std::array<double、integer>?
- 编译器错误:函数调用在常量表达式中必须有一个常量值
- 错误:'new'不能出现在常量表达式中
- 我可以写出小于 -0.5 两个 ulps 的常量表达式双精度吗?
- 编译器在传递 const 变量时返回错误:模板参数不是常量表达式
- 为什么我不能在非常量表达式上使用此模板阶乘函数?
- C++ 使用变量而不是常量表达式初始化数组
- 使用函数参数作为常量表达式的一部分 - gcc vs clang
- 片段着色器中的"错误:在 GLSL 1.30 及更高版本中禁止使用非常量表达式索引的采样器数组"