Почему я должен заключить в скобки инициализирующее выражение, которое является выражением запятой?
Разбирая проблему, я имею в виду ее сущность, я могу инициализировать переменную как 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
, так что разбора не получается.