2015-05-20 4 views
3

Я хочу создать if, где переменная объявляется, назначается и проверяется. Если значение переменной приемлемо, я хочу использовать его внутри тела if. Вот пример того, как я думал, что я мог бы сделать это:Почему следующий код является незаконным в C++

if ((int result = Foo()) != 0) { 
    // use result 
} 

Я предположил, что Foo() возвращает некоторое значение, которое присваивается result, и возвращает оператор присваивания =, и, наконец, сверяется 0 в != 0. К сожалению, это приводит к ошибке компиляции:

main.cpp:31:10: error: expected primary-expression before ‘int’ 
if ((int i = Foo()) != 0) 
    ^           
main.cpp:31:10: error: expected ‘)’ before ‘int’ 

Почему эта ошибка происходит? И какие могли бы исправить это?

+1

объявлять 'Int result' за пределами, если, например, прежде чем пытаться его использовать. –

+0

Если вы плохо злоупотребляете языком, вы можете сделать что-то вроде struct Foo {operator int() {return 42; }}; for (int i = Foo(); i! = 0;) {/ * do stuff */break; } –

+0

Ну, ваша логика применима, если бы у вас действительно был «оператор присваивания» в вашем коде. Но вы этого не сделаете. '=' Не является оператором вообще, а 'int result = Foo()' не является выражением. Это декларация. Декларация не является выражением, которое требует особого отношения к этой ситуации и налагает ограничения на ее удобство использования. – AnT

ответ

3

Вашего рассуждения кажется, основано на предположении, что = в

if ((int result = Foo()) != 0) 

является оператором присваивания и int result = Foo() «просто выражение», которое вычисляется что нибудь.

Это неправда.

Часть int result = Foo() не является выражением в C++. Это объявление с инициализатором. = в синтаксисе инициализатора вообще не является оператором присваивания. Это просто синтаксический элемент, который по совпадению использует тот же символ, что и оператор присваивания. int result = Foo() не является выражением и не «оценивает» ни один результат.

Потому что, если выше, поддержка что-то вроде

if (int result = Foo()) 

требует специального лечения, что существенно ограничивает гибкость этого синтаксиса. То, что вы пробовали в своем коде, выходит за рамки того, что разрешено этим особым режимом.

+0

Ладно, наверное, у меня больше нет вопросов. Спасибо за ответ! – Saage

7

Логика поддерживается, но объявление переменной в операторе if и использование этого способа - нет. Причина связана с тем, что инициализатор работает иначе, чем обычное задание, но работа вокруг этого проста и тривиальна.

Просто сделайте что-нибудь подобное.

int result; 

if ((result = Foo()) != 0) { 
    // use result 
} 
+2

... и добавьте дополнительную область, если вы хотите, чтобы «результат» имел конкретную продолжительность жизни, связанную с оператором 'if'. –

+3

«объявление переменной в выражении if не поддерживается» - это на самом деле. Запись if (int result = Foo()) {/ * использование результата * /} компилируется и работает как ожидалось. – Saage

+3

Это неверно, вы можете объявить переменную в условии оператора if, черновик стандартного раздела '6.4p3' –

0

Он терпит неудачу, потому что это незаконно. Это тоже уродливо. @Jonathan Wood предложил объявить переменную за пределами if. Я предлагаю вызова Foo снаружи, тоже:

int result = Foo(); 
if(result!=0) ... 

(x=f())!=y конструкт, в то время как юридическое, как if состоянии, имеет смысл только в цикле, где

`в то время как ((с = GetChar()) = «\ п) ... сделать что-то с с ...

ли короче и лучше эквивалент

c = getchar(); 
while(c!='\n') 
{ 
    ... 
    c = getchar(c); 
} 

Это са ves записывает вызов getchar() дважды. Он ничего не сохраняет при использовании в if, поэтому нет смысла его использовать.

+0

Я просто не понимаю, почему это незаконно. Настоящая причина, по которой я пробовал эту конструкцию, состоял в том, что я пытался проверить, существует ли какая-либо пара ключей-значений на карте, например ((map :: iterator it = mymap.find (1))! = Mymap.end() && it-> second == 1) {/ * do stuff * /}. Это не красиво, но это имеет смысл сделать это в одном заявлении. – Saage

2

Bjarne использует эту конструкцию как ограничитель объема в 6.3.2.1 Язык программирования C++ в качестве рекомендации.

Использование:

if (int result = Foo()) { 
    // use non-zero result 
} 

Это особенно полезно с указателями

if (Foo* result = GetFoo()) { 
    // use valid Foo 
} 

!=0 часть увольняемых truthiness является !=0.

Расширенная конструкция с сопоставлением не допускается.

Дальнейшее обсуждение этой конструкции из here

0

Попробуйте это:

if (int i = (Foo() != 0) ? Foo() : 0){ 
     cout << "Hello. Number i = " << i; 
    } 
+0

Будьте осторожны, если оценка Foo() имеет побочные эффекты. –

Смежные вопросы