Давайте возьмем этот простой пример:
#include <iostream>
namespace foo {
constexpr int main(int argc, char* argv[]) {
// code
}
}
int main(int argc, char* argv[])
{
return foo::main(argc, argv);
}
Зависит от того, что код есть, лязг будет жаловаться или нет. Если код:
cout << "Hello!";
return 0;
лязг жалуется:
ошибка: функция constexpr никогда не выдает постоянное выражение
[-Winvalid-constexpr]constexpr int main(int argc, char* argv[]) {
примечание: оператор non-constexpr ‘оператор<< >»
нельзя использовать в постоянном выраженииstd::cout << "Hello!";
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:530:5:
примечание: заявлено здесьoperator<<(basic_ostream<char, _Traits>& __out, const char* __s)
Как мы знаем, функции constexpr не могут содержать никаких операторов cout. Но что произойдет, если мы сделаем это?
for (int i = 0; i < argc; i++)
std::cout << argv[i];
лязг это позволяет! Хорошо, но это не может быть функция constexpr, даже если она помечена как constexpr, давайте попробуем использовать ее в контексте constexpr.
int arr[foo::main(argc, argv)];
Оно работает! Так должно быть лягушатник? Причина, по которой я говорю «лязг», потому что gcc жалуется:
ошибка: тело функции constexpr ‘constexpr int foo :: main (int,
char **) ‘не возвращение
Итак, мой вывод — лязг — это неправильно, а gcc — правильно.
Вы компилируете свой код в режиме C ++ 1y, который содержит формулировку для расслабления constexpr
ограничения, включая все циклические операторы.
Посмотри на N3652 который ввел эти изменения.
Clang здесь прав.
Первый пример
Вот код:
constexpr int foo::main(int argc, char* argv[]) {
std::cout << argv[i];
return 0;
}
В С ++ 11, этот код плохо сформирован, потому что тело содержит Выражение-заявление, что не разрешено в constexpr
определение функции.
В С ++ 1й, этот код некорректен без необходимости диагностики, потому что вызов foo::main
никогда не может произвести постоянное выражение (потому что оно всегда вызывает operator<<(std::ostream&, const char*)
, который не constexpr
).
Второй пример
В этом случае код:
constexpr int foo::main(int argc, char* argv[]) {
for (int i = 0; i < argc; i++)
std::cout << argv[i];
return 0;
}
В С ++ 11, этот код плохо сформирован, потому что он содержит for
-заявление.
В С ++ 1й, этот код действителен Особенно, foo::main(0, 0)
является константным выражением (со значением 0
). поскольку foo::main
может использоваться в константном выражении, Clang не разрешается отклонять его и не делает этого.
Третий пример
int arr[foo::main(argc, argv)];
Массив, связанный здесь не константное выражение (потому что оно читает argc
а также argv
, которые не являются постоянными). Однако Clang поддерживает массивы переменной длины как расширение по умолчанию. Вы можете указать -pedantic-errors
перевести clang в строго соответствующий режим, и в этом режиме он отклонит этот код.
Диагностика GCC:
ошибка: тело функции constexpr ‘constexpr int foo :: main (int, char **)’ не является оператором возврата
неверно в C ++ 11 и C ++ 1y. В C ++ 11 это неверно, потому что правило более тонкое (тело constexpr
функция может содержать typedef
S и несколько других конструкций, а не только return
-заявления). В C ++ 1y правило больше не существует вообще.
Таким образом, gcc 4.8.1 не реализует смягченные ограничения constexpr, но clang 3.5 делает. Моя ошибка состояла в том, что у clang и gcc оба есть расширения массива переменной длины. если бы я использовал вместо этого std :: array, оба компилятора отклонили бы код. Что я до сих пор не понимаю, так это то, что если clang позволяет использовать relaxtex constexpr, то почему он не является constexpr?