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