В процессе ответа этот вопрос на ТА для 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.
Да, я считаю, что это изменение между C ++ 03 и C ++ 11. Я полагаю, что это было сделано примерно по той причине, на которую вы намекаете — что нет особенно веской причины, по которой оператор запятой не может быть частью константного выражения.
Я считаю, что правило в C ++ 03 возникло из правила в C (C90, §6.4):
Выражения констант не должны содержать операторов присваивания, приращения, декремента, вызова функции или запятой, за исключением случаев, когда они содержатся в операнде размер оператор.
Относительно того, почему оператор запятой был запрещен в константных выражениях в C, я могу только догадываться. Мое непосредственное предположение должно было бы гарантировать, что определение как:
int x[2, 5];
…будет отвергнуто вместо того, чтобы оставить пользователя с ошибочным убеждением, что он определил массив элементов 2×5, когда (если оператор запятых там был разрешен) он действительно определил 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];
все еще плохо сформирован.