为什么我可以在 constexpr 函数内调用非 constexpr 函数?

问题描述 投票:0回答:2

考虑以下代码:

#include <stdio.h>

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

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

我本以为编译器会抱怨

printf
中对
f
的调用,因为
f
应该是
constexpr
,但
printf
不是。为什么程序编译并打印15

c++ gcc c++11 constexpr side-effects
2个回答
14
投票

该程序是格式错误,根据C++11标准草案部分

7.1.5
constexpr说明符段落5

不需要诊断,其中说:

对于 constexpr 函数,如果不存在这样的函数参数值 函数调用替换会产生一个常量 表达式(5.19),程序格式错误;无需诊断。

并提供以下示例:

constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required

和第
5.192

段说:

条件表达式是核心常量表达式,除非它 涉及以下内容之一作为潜在评估的子表达式 [...]

并包括:

— 对 constexpr 构造函数之外的函数的调用 文字类或 constexpr 函数 [注意:重载解析 (13.3)照常应用——尾注];

在这种情况下我们可能更喜欢诊断,这可能只是一个疏忽,我有一个类似情况的错误报告,其中
gcc不会产生错误,但我们可能希望它:编译器是否允许有余地它认为常量表达式中的未定义行为是什么?

更新

使用 
-fno-builtin
 标志将导致 
gcc

生成以下错误:

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

所以
gcc确实考虑了这个格式错误
,只是在使用内置版本的
printf

时忽略了它。

尽管使用 
-pedantic

的方式有些不一致,但会产生以下警告:

warning: ISO C++ forbids variable length array 'a' [-Wvla] char a[f()]; ^

请注意,使用 
f() 来初始化 constexpr

变量:

constexpr int x = f() ;

确实产生错误:

error: 'printf(((const char*)"a side effect!\012"))' is not a constant expression

请注意,另外在更一般的情况下,不允许编译器将标准库函数标记为 constexpr 除非标准明确允许


0
投票

该程序自 C++23 起合法。

C++23 允许您将(几乎)任何函数标记为 
constexpr,即使不可能在编译时求值。在您的情况下,该函数将在运行时运行。仅当您尝试“强制”它在编译时运行时,才会出现错误,例如将结果分配给 constexpr
 变量。

© www.soinside.com 2019 - 2024. All rights reserved.