Why can I call a non-constexpr function inside a c

2019-01-11 14:16发布

问题:

Consider the following code:

#include <stdio.h>

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

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

I would have expected the compiler to complain about the call to printf inside f, because f is supposed to be constexpr, but printf is not. Why does the program compile and print 15?

回答1:

The program is ill-formed and requires no diagnostic according to the C++11 draft standard section 7.1.5 The constexpr specifier paragraph 5 which says:

For a constexpr function, if no function argument values exist such that the function invocation substitution would produce a constant expression (5.19), the program is ill-formed; no diagnostic required.

and provides the following example:

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

and section 5.19 paragraph 2 says:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...]

and includes:

— an invocation of a function other than a constexpr constructor for a literal class or a constexpr function [ Note: Overload resolution (13.3) is applied as usual —end note ];

We would probably prefer a diagnostic in this case, it could just be an oversight, I have a bug report for a similar situation where gcc does not produce an error but we would probably like it to: Is the compiler allowed leeway in what it considers undefined behavior in a constant expression?.

Update

Using the -fno-builtin flag will cause gcc to generate the following error:

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

So gcc does consider this ill-formed it is just ignores it when it is using the builtin version of printf.

Although somewhat inconsistently using the -pedantic produces the following warning:

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

Note that using f() to initialized a constexpr variable:

constexpr int x = f() ;

does generate an error:

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

Note that additionally in the more general case a compiler is not allowed mark standard library functions as constexpr unless explicitly allowed by the standard.