Разрешен ли оператор запятой в выражении константы в C++11?

В процессе ответа на этот вопрос о SO для C++11 я понял, что в C++03 (как и в C) использование оператора запятой явно запрещено в константном выражении.

Пункт 5.19/1 стандарта C++ 03 по константным выражениям гласит:

[...] В частности, кроме выражений sizeof, функции, объекты класса, указатели или ссылки не должны использоваться, а операторы присваивания, приращения, уменьшения, вызова функции илизапятой не должны использоваться.

Однако в C++11 последняя часть, в которой упоминается оператор запятой, кажется, исчезла. И хотя в параграфе 5.19/2 стандарта C++11 четко указано, что присваивание, приращение, уменьшение иconstexprВыражения вызова функций не должны появляться как подвыраженияконстантного выражения, использование оператора запятой, как представляется, больше не запрещено.

Например, следующая программа прекрасно компилируется на GCC 4.7.2 и Clang 3.3 с std=c++11 (кроме предупреждений компилятора о том, что оператор запятой не имеет никакого эффекта иxа такжеarrпеременные не используются):

int main()
{
    constexpr int x = (0, 42);
    int arr[(0, 42)];
}

Однако следует сказать, что даже следующая программа прекрасно компилируется с-std=c++03 опция (как для Clang, так и для GCC), которая явно неверна, учитывая приведенную выше цитату из стандарта C++ 03:

int main()
{
    int arr[(0, 42)];
}

ВОПРОС:

Есть ли разница между C++ 03 и C++11 в том, разрешен или нет оператор запятой в константном выражении, или я что-то упустил?

В качестве дополнительного (неконструктивного) вопроса мне было бы интересно узнать, почему оператор запятой нельзя использовать в константном выражении в C++03.

2 ответа

Решение
  1. Да, я считаю, что это изменение между C++03 и C++11. Я полагаю, что это было сделано примерно по той причине, на которую вы намекаете - что нет особой причины, по которой оператор запятой не может быть частью константного выражения.

  2. Я считаю, что правило в C++03 возникло из правила в C (C90, §6.4):

Выражения констант не должны содержать операторы присваивания, приращения, декремента, вызова функции или запятой, за исключением случаев, когда они содержатся в операнде оператора sizeof.

Что касается того, почему оператор запятой был запрещен в константных выражениях в C, я могу только догадываться. Мое непосредственное предположение должно было бы гарантировать, что определение как:

int x[2, 5];

... будет отвергнут вместо того, чтобы оставить пользователя с ошибочным убеждением, что он определил массив элементов 2x5, когда (если оператор запятой там был разрешен) он действительно определил x всего 5 элементов.

Однако следует сказать, что даже следующая программа прекрасно компилируется с опцией -std= C++03 (как для Clang, так и для GCC), что явно неверно, учитывая приведенную выше цитату из стандарта C++03

Не так быстро. Вы также должны использовать -pedantic (или же -pedantic-errors) заставить Clang и GCC строго соблюдать правила C++03. С этим, ствол GCC говорит:

<stdin>:1:16: error: array bound is not an integer constant before ‘]’ token

и лязг ствола говорит:

<stdin>:1:19: error: variable length arrays are a C99 feature [-Werror,-Wvla-extension]
void f() { int arr[(0, 42)]; }
                  ^

Как вы заметили, этот код действителен C++11. Однако запятые верхнего уровня все еще недопустимы в C++ 11, потому что константное выражение в грамматике C++ 11 является разновидностью условного выражения (где запятая верхнего уровня не допускается). Таким образом:

int arr[0, 42];

все еще плохо сформирован.

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