Почему я могу вызвать функцию не-constexpr внутри функции constexpr?

Рассмотрим следующий код:

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

1 ответ

Решение

Программа некорректна и не требует диагностики в соответствии с разделом проекта стандарта C++11 7.1.5 Параграф5 спецификатора constexpr, который гласит:

Для функции 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.19 пункт 2 гласит:

Условное выражение является основным константным выражением, если оно не включает одно из следующего в качестве потенциально вычисляемого подвыражения [...]

и включает в себя:

- вызов функции, отличной от конструктора 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, если это явно не разрешено стандартом.

Другие вопросы по тегам