GCC рассматривает встроенные функции непостоянных выражений как постоянные выражения
Пожалуйста, смотрите обновление для лучшего примера проблемы. Оригинальный код имеет множество проблем, которые запутывают картину:
Этот вопрос Почему я могу вызвать функцию не-constexpr внутри функции constexpr? представил следующий код
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!\n");
}
int main()
{
char a[f()];
printf("%zd\n", sizeof a);
}
Который, как я отвечаю, плохо сформирован, но gcc 4.8.2
позволяет это ( увидеть это в прямом эфире).
Но если мы используем -fno-builtin
флаг gcc
генерирует ошибку ( смотрите вживую):
error: call to non-constexpr function 'int printf(const char*, ...)'
return printf("a side effect!\n");
^
так что seems
тот gcc
рассматривает его встроенную версию printf
быть постоянным выражением. gcc
документирует встроенные функции здесь, но не документирует этот случай, когда встроенная функция не-constexpr может рассматриваться как константное выражение.
Если это действительно так:
- Разрешено ли это делать компилятору?
- Если они разрешены, не должны ли они документировать это, чтобы соответствовать?
- Можно ли считать это расширением, если это так, кажется, что для этого потребуется предупреждение, как в разделе проекта стандарта C++
1.4
Реализация соответствия пункта 8 гласит (выделено мое)
Соответствующая реализация может иметь расширения (включая дополнительные библиотечные функции), при условии, что они не изменяют поведение любой правильно сформированной программы. Внедрения необходимы для диагностики программ, использующих такие расширения, которые неправильно сформированы в соответствии с настоящим международным стандартом. Сделав это, однако, они могут компилировать и выполнять такие программы.
Обновить
Как указывает Кейси, в исходной задаче происходит несколько вещей, которые делают ее плохим примером. Простым примером будет использование std::pow, который не является функцией constexpr:
#include <cmath>
#include <cstdio>
constexpr double f()
{
return std::pow( 2.0, 2.0 ) ;
}
int main()
{
constexpr double x = f() ;
printf( "%f\n", x ) ;
}
Компилирует и строит без предупреждений или ошибок ( смотрите его вживую), но с добавлением -fno-builtin
делает это генерирует ошибку ( см. это вживую). Примечание: почему математические функции не являются constexpr в C++ 11:
error: call to non-constexpr function 'double pow(double, double)'
return std::pow( 2.0, 2.0 ) ;
^
2 ответа
Да, gcc
рассматривает некоторые встроенные функции как constexpr, даже если стандарт явно не помечает их как таковые. Мы можем найти обсуждение, которое относится конкретно к математической функции, найденной в cmath
в gcc
отчет об ошибке [C++0x] sinh vs asinh vs constexpr, который говорит:
LWG 2013, похоже, позволяет GCC рассматривать эти функции как constexpr. Итак, исправлено 4,7
который относится к выпуску 2013 года LWG, первоначальное предлагаемое решение которого заключалось в добавлении следующего к разделу 17.6.5.6
[constexpr.functions] (выделение будет идти вперед):
[...] Кроме того, реализация может объявить любую функцию как constexpr, если определение этой функции удовлетворяет необходимым ограничениям [...]
но после C++11 разрешение было отменено, и окончательное разрешение получилось следующим образом:
[...] Реализация не должна объявлять какую-либо сигнатуру стандартной библиотечной функции в качестве constexpr, за исключением тех, где это явно требуется.[..]
Так что в настоящее время это (в C++ 14) явное несоответствующее расширение, и, насколько я могу судить, это было несоответствующим в C++11, поскольку оно изменяет наблюдаемое поведение и, следовательно, не будет разрешено через as-if правило
Джонатан Уэйкли указывает на libstdc++
обсуждение списка рассылки: PR libstdC++/49813 (пересмотрено): constexpr по функциям (и встроенным функциям), в которых обсуждалось повторное открытие отчета об ошибке, упомянутого выше, из-за проблем, изложенных выше:
Я считаю, что мы должны заново открыть ошибку в свете фактического разрешения LWG 2013 (добавление constexpr запрещено).
FE не должен рассматривать встроенные объекты как constexpr в режиме строгого соответствия.
Мы должны либо полностью удалить _GLIBCXX_CONSTEXPR из
, либо сделать его условным для __STRICT_ANSI__.
GCC не считает f()
быть постоянным выражением. Посмотрите на диагностику для первой программы, которую вы связали:
main.cpp: в функции 'int main()': main.cpp:10:19: предупреждение: ISO C++ запрещает массив переменной длины 'a' [-Wvla] char a[f()]; ^
Компилятор не думает f()
является константным выражением, программа фактически использует расширение GCC, которое допускает массивы переменной длины - массивы с непостоянным размером.
Если вы измените программу, чтобы заставить f()
в постоянное выражение:
int main() {
constexpr int size = f();
char a[size];
printf("%zd\n", sizeof a);
}
main.cpp: в функции 'int main()': main.cpp:10:32: в расширении constexpr 'f()' main.cpp:5:41: ошибка: 'printf(((const char*)"побочный эффект!\012")) "не является константным выражением return printf ("побочный эффект!\n"); ^