Что неправильно с объявлением переменной внутри if condition? - программирование
Подтвердить что ты не робот

Что неправильно с объявлением переменной внутри if condition?

Возможно, я становлюсь ржавым (недавно писал на Python).

Почему это не компилируется?

if ( (int i=f()) == 0)

без () вокруг int i=f() я получаю другую, гораздо более разумную ошибку i не является логическим. Но вот почему я хотел скобок в первую очередь!

Мое предположение заключалось бы в том, что использование круглых скобок делает его выражением, и это выражение объявления не допускается в выражении. Это так? И если да, является ли это одним из синтаксических особенностей С++?

Кстати, я действительно пытался это сделать:

if ( (Mymap::iterator it = m.find(name)) != m.end())
    return it->second;
4b9b3361

Ответ 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, и это должно быть первое условие, если ваш компилятор применяет оценку слева направо.

Но, к сожалению, это не применимо в случае итераторов, как ваш второй пример спрашивает.