C++ gcc是否认为非常量表达式函数的内置函数是常量表达式
请参阅更新以获得问题的更好示例。原始代码有一系列问题,这些问题使情况变得混乱: 这个问题给出了以下代码C++ gcc是否认为非常量表达式函数的内置函数是常量表达式,c++,gcc,c++11,language-lawyer,constant-expression,C++,Gcc,C++11,Language Lawyer,Constant Expression,请参阅更新以获得问题的更好示例。原始代码有一系列问题,这些问题使情况变得混乱: 这个问题给出了以下代码 #include <stdio.h> constexpr int f() { return printf("a side effect!\n"); } int main() { char a[f()]; printf("%zd\n", sizeof a); } 因此似乎认为gcc的内置版本printf是一个常量表达式gcc,但没有说明非constexp
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!\n");
}
int main()
{
char a[f()];
printf("%zd\n", sizeof a);
}
因此似乎认为gcc
的内置版本printf
是一个常量表达式gcc
,但没有说明非constexpr函数的内置函数可以被视为常量表达式的情况
如果情况确实如此:
- 是否允许编译器执行此操作
- 如果他们被允许,他们不需要记录下来以符合要求吗
- 这是否可以被视为一种扩展,如果是这样的话,这似乎需要一个警告,正如
1.4节实施合规性第8段所述(重点):
一致性实现可能具有扩展(包括附加的库函数),前提是它们不会改变任何格式良好的程序的行为根据本国际标准,需要实施来诊断使用此类扩展的程序,这些扩展的格式不正确。然而,这样做之后,他们就可以编译和执行这样的程序了
更新
正如Casey指出的,原始问题中存在一些问题,这使得它成为一个糟糕的例子。一个简单的例子是使用非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 ) ;
}
GCC没有考虑<代码> f-()/代码>是一个常量表达式。查看以下诊断:
:
main.cpp:在函数“int main()”中:
main.cpp:10:32:in-constexpr扩展'f()'
main.cpp:5:41:错误:“printf(((const char*)“副作用!\012”)”不是常量表达式
返回printf(“副作用!\n”);
^ 是的,gcc
正在考虑将一些作为constexpr,即使标准没有明确地将它们标记为constexpr。我们可以在gcc
bug报告中找到专门与cmath
中的数学函数相关的讨论,其中指出:
LWG 2013似乎允许GCC将这些函数视为constexpr。
所以,固定为4.7
指其最初提议的决议是将以下内容添加到第17.6.5.6节[施工图功能](重点放在后面):
[…]此外,一个实现可以声明任何要执行的函数
constexpr,如果该函数的定义满足
限制[……]
但在C++11之后,分辨率被颠倒,最终分辨率为:
[…]实现不应声明任何标准库函数
作为constexpr的签名,除非明确
必需。[..]
这是目前(在C++14中)的情况,据我所知,这在C++11中是不一致的,因为它改变了可观察的行为,因此通过“仿佛”规则是不允许的
Jonathan Wakely指出了一个libstdc++
邮件列表讨论:由于上述问题,讨论了重新打开上述bug报告的问题:
我认为我们应该根据实际解决方案重新打开bug
LWG 2013年版(禁止添加constexpr)
FE不应严格按照constexpr处理内置项
模式
我们应该将_GLIBCXX_CONSTEXPR完全从
以严格的ANSI为条件
你认为gcc到底违反了什么?是不是[dcl.constexpr]/5“对于一个constexpr函数,如果没有函数参数值存在,函数调用替换将产生一个常量表达式(5.19),那么程序是错误的;不需要诊断。”?注意:我不太明白为什么在gcc拒绝它时,你说“gcc 4.8.2允许它”,调用f()
不是一个常量表达式。但是,它没有拒绝的是函数f
本身的定义,对于它来说,不需要诊断。我不相信它将内置函数视为常量表达式。您没有提供一个例子来证明这一点(调用f()
,导致调用printf(“副作用!\n”)
并不是一个常量表达式)。[续..]当切换到-fno-builtin
时,它还诊断f
本身的病态。现在的问题是:“gcc用不同的开关显示不同的行为是一致的吗?”还是“gcc接受非常量表达式作为数组绑定是一致的?”还是“gcc在不拒绝f
时是一致的?”嗯,这个例子在我看来更好。f
格式仍然不正确,不需要诊断,但x=f()
格式不正确,我认为需要诊断。接受该程序是一个扩展,不产生任何关于它的消息是不合格的。关于strlen的例子,我必须再看一次另一个例子。@ShafikYaghmourstrlen
没有副作用。很可能是constexpr
,我要说的是,对于gcc+args的特殊风格,它是constexpr
。有趣的是,C++1y(无论如何,N3936)17.6.5.6[constexpr.functions]/1可能禁止这种行为:“本标准明确要求某些标准库函数为constexpr(7.1.5)。实现不应将任何标准库函数签名声明为constexpr,除非明确要求。”如果它生成错误:error:call to non-constexpr function'size_t strlen(const char*)”
@ShafikYaghmour是的,我知道-因此我的声明是“针对特定风格的gcc+args”。+1最初的示例发生了太多事情,所以我更新了我的问题,并添加了一个更简单的示例,使用std::pow
#include <cmath>
#include <cstdio>
constexpr double f()
{
return std::pow( 2.0, 2.0 ) ;
}
int main()
{
constexpr double x = f() ;
printf( "%f\n", x ) ;
}
error: call to non-constexpr function 'double pow(double, double)'
return std::pow( 2.0, 2.0 ) ;
^
main.cpp: In function 'int main()':
main.cpp:10:19: warning: ISO C++ forbids variable length array 'a' [-Wvla]
char a[f()];
^
int main() {
constexpr int size = f();
char a[size];
printf("%zd\n", sizeof a);
}
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");
^