Что неправильно с объявлением переменной внутри if condition?
Возможно, я становлюсь ржавым (недавно писал на Python).
Почему это не компилируется?
if ( (int i=f()) == 0)
без ()
вокруг int i=f()
я получаю другую, гораздо более разумную ошибку i
не является логическим. Но вот почему я хотел скобок в первую очередь!
Мое предположение заключалось бы в том, что использование круглых скобок делает его выражением, и это выражение объявления не допускается в выражении. Это так? И если да, является ли это одним из синтаксических особенностей С++?
Кстати, я действительно пытался это сделать:
if ( (Mymap::iterator it = m.find(name)) != m.end())
return it->second;
Ответы
Ответ 1
Вы можете объявить переменную в инструкции if
в С++, но ее можно использовать с прямой инициализацией, и ее нужно преобразовать в логическое значение:
if (int i = f()) { ... }
У С++ нет ничего, что можно было бы назвать "выражением объявления", т.е. [под] выражениями, объявляющими переменную.
Собственно, я просто просмотрел предложение в стандарте, и обе формы инициализации поддерживаются в соответствии с пунктом 6.4 [stmt.select]:
...
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
...
То есть, также можно написать:
if (int i{f()}) { ... }
Очевидно, что это работает только в С++ 2011, потому что С++ 2003 не имеет инициализации скобок.
Ответ 2
Там проблема с областью.
Рассмотрим следующий код:
if ((int a = foo1()) || (int b = foo2()))
{
bar(b);
}
Объявлено ли b внутри блока? Что делать, если foo1()
возвращает true?
Ответ 3
Вы можете объявить переменную в выражении if (или in for или while), но только во внешнем блоке скобок, и она должна быть преобразована в bool.
Ваша догадка в принципе правильная, она не допускается, потому что
(int i = 42;)
не является допустимым объявлением с инициализацией.
Вам нужна еще одна строка,
Mymap::iterator it;
if ( (it = m.find(name)) != m.end())
return it->second;
но тогда лучше написать
Mymap::iterator it = m.find(name);
if ( it != m.end() )
return it->second;
Вы можете поместить строку return
после if
, если вы действительно хотите вернуть эту строку, по крайней мере, для меня это не повредит читаемости, но другие могут видеть, что разные.
Если вы действительно хотите объявить итератор и использовать его как bool в состоянии if
, вы можете сделать
if ( struct { int it; operator bool() { return it != m.end; } } s = { m.find(name) } )
return s.it->second;
но я считаю это вредным; -)
Ответ 4
Это правда, что вы не можете писать
if ( (int i=f()) == 0)
но вы можете отлично писать
if ( int i=f())
Таким образом, вы можете использовать оператор &&
для выполнения обеих операций в одном выражении типа
if ( int i=1 && (i=f()) == 0)
i
должен быть инициализирован любым значением, отличным от 0, и это должно быть первое условие, если ваш компилятор применяет оценку слева направо.
Но, к сожалению, это не применимо в случае итераторов, как ваш второй пример спрашивает.