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

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

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

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

Однако в 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 Standard:

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

ВОПРОС:

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

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

22

Решение

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

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

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

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

int x[2, 5];

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

14

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

Однако следует сказать, что даже следующая программа прекрасно компилируется с опцией -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];

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

3