ошибка constexpr в clang, но не в gcc?

Давайте возьмем этот простой пример:

#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 — правильно.

4

Решение

Вы компилируете свой код в режиме C ++ 1y, который содержит формулировку для расслабления constexpr ограничения, включая все циклические операторы.

Посмотри на N3652 который ввел эти изменения.

2

Другие решения

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 функция может содержать typedefS и несколько других конструкций, а не только return-заявления). В C ++ 1y правило больше не существует вообще.

10

Таким образом, gcc 4.8.1 не реализует смягченные ограничения constexpr, но clang 3.5 делает. Моя ошибка состояла в том, что у clang и gcc оба есть расширения массива переменной длины. если бы я использовал вместо этого std :: array, оба компилятора отклонили бы код. Что я до сих пор не понимаю, так это то, что если clang позволяет использовать relaxtex constexpr, то почему он не является constexpr?

0
По вопросам рекламы [email protected]