Почему я должен заключить в скобки инициализирующее выражение, которое является выражением запятой?

Разбирая проблему, я имею в виду ее сущность, я могу инициализировать переменную как int, выполнив вначале лямбду бездействия в выражении через запятую, например так:

int main(){
  auto x = ( []{}(), 10 );          // same effect as auto x = 10;
}

Но если я не заключу в скобки инициализирующее выражение,

int main(){
  auto y = []{}(), 10;              // won't compile
}

все gcc, clang и MSVC жалуются на попытки инициализации y с void выражение.

Почему я должен заключить в скобки выражение запятой, чтобы использовать его в качестве инициализатора?

1 ответ

В декларации , Символ отделяет деклараторов. Более простой пример:

int i = 2, j = 3;     // OK: declares `i` and `j`
int i = 2, 3;         // Error: `3` is not a declarator

Во втором случае это выглядит неоднозначно. Это , разделители, или это , часть выражения 2, 3?

Чтобы устранить эту неоднозначность, мы можем обратиться к грамматике языка (C++14 [dcl.decl]):

простая декларация:
decl-specier-seqopt init-декларатор-списокopt ;
атрибут-спецификатор-seq decl-спецификатор-seqopt init-Заявитель-список ;

INIT-описатель-лист:
INIT-описатель
INIT-описатель-лист , INIT-описатель

INIT-описатель:
декларатор инициализаторопт

То, как работают грамматики, это означает, что при разборе объявления самая длинная возможная последовательность, которая соответствует init-декларатору, Считается. (Это иногда называют "принципом максимального жаворонка"). Так int i = 2, соответствует init-декларатору,, затем 3 не соответствует init-declarator, так что разбора не получается.

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