【发布时间】:2014-03-04 20:34:04
【问题描述】:
请查看更新以获得更好的问题示例。原始代码混合了一些混淆图片的问题:
这个问题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 视为常量表达式。 gcc documents builtins here 但没有记录这种情况,即非 constexpr 函数的内置函数可以被视为常量表达式。
如果确实如此:
- 允许编译器这样做吗?
- 如果他们被允许,他们是否不必记录它以符合要求?
- 这是否可以被视为扩展,如果是这样,这似乎需要一个警告,因为 C++ draft standard 部分
1.4实施合规性 段落 8 说( 强调我的):
只要不改变任何格式良好的程序的行为,符合标准的实现可能具有扩展(包括额外的库函数)。 根据本国际标准,诊断使用此类格式错误的扩展程序的程序需要实现。然而,这样做之后,他们就可以编译和执行这样的程序了。
更新
正如凯西指出的那样,原始问题中发生了一些事情,使其成为一个糟糕的例子。一个简单的例子是使用不是 constexpr 函数的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 ) ;
}
编译和构建没有警告或错误 (see it live),但添加 -fno-builtin 会产生错误 (see it live)。注:why math functions are not constexpr in C++11:
error: call to non-constexpr function 'double pow(double, double)'
return std::pow( 2.0, 2.0 ) ;
^
【问题讨论】:
-
你认为 gcc 到底违反了什么?是不是 [dcl.constexpr]/5 “对于 constexpr 函数,如果不存在函数参数值使得函数调用替换会产生常量表达式 (5.19),则程序格式错误;不需要诊断。” ?
-
注意:我不太明白为什么当 gcc 拒绝它时你说“gcc 4.8.2 允许它”,调用
f()是不是一个常量表达式。然而,它不拒绝的是函数f本身的定义,AFAIK 不需要诊断。 -
我不相信它会将内置函数视为常量表达式。您没有提供证明这一点的示例(并且调用
f(),导致调用printf("a side effect!\n")不被视为常量表达式)。 -
[继续..] 当切换到
-fno-builtin时,它也诊断f本身的格式错误。现在的问题是:“gcc 使用不同的开关显示这种不同的行为是否符合要求?”还是“gcc 接受非常量表达式作为数组绑定是否符合要求?”还是“当不拒绝f时,gcc是否符合?” -
嗯,这个例子是更好的 IMO。
f仍然格式不正确,不需要诊断,但x = f()格式不正确我认为需要进行诊断。接受程序是一种扩展,不产生任何关于它的消息是不合格的。
标签: c++ gcc c++11 language-lawyer constant-expression