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

fre*_*low 16 c++ gcc side-effects constexpr c++11

请考虑以下代码:

#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)

我本来期望编译器抱怨printf内部的调用f,因为f应该是constexpr,但printf不是.为什么程序编译和打印15

Sha*_*our 11

该方案是形成不良的,并且不需要诊断根据标准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
Run Code Online (Sandbox Code Playgroud)

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");
                                 ^
Run Code Online (Sandbox Code Playgroud)

因此,gcc不考虑这种病态的,当它使用的内置版本,它只是忽略它printf.

虽然使用时有些不一致-pedantic会产生以下警告:

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

请注意,使用f()初始化constexpr变量:

constexpr int x = f() ;
Run Code Online (Sandbox Code Playgroud)

会产生错误:

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

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