что плохого в объявлении переменной внутри условия if?

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

почему это не компиляция?

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

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

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

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

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

4 ответов


вы можете объявить переменную в if оператор в C++, но он ограничен для использования с прямой инициализацией, и его необходимо преобразовать в логическое значение:

if (int i = f()) { ... }

C++ не имеет ничего, что можно было бы описать как "выражение объявления", т. е. [sub-] выражения, объявляющие переменную.

на самом деле, я просто посмотрел предложение в стандарте, и обе формы инициализации поддерживаются в соответствии с 6.4 [stmt.выберите пункт 1:

...
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()}) { ... }

очевидно, что это работает только в C++2011, потому что C++2003 не имеет инициализации скобки.


есть проблема с областью.

рассмотрим следующий код:

if ((int a = foo1()) || (int b = foo2()))
{
    bar(b);
}

объявлен ли b внутри блока? Что, если ... --1--> возвращает true?


вы можете объявить переменную в операторе if (или в 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;

но я бы счел это вредным ; -)


Это правда, что вы не можете писать

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

но вы можете прекрасно написать

if ( int i=f())

таким образом, вы можете использовать && оператор для выполнения обеих операций в одном операторе, как

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

i должно быть инициализировано любым значением, отличным от 0, и это должно быть первое условие, если ваш компилятор применяет оценку слева направо.

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