Подтвердить что ты не робот

Почему я не могу поместить объявление переменной в тестовую часть цикла while?

Вы можете, очевидно, поместить объявление переменной в цикл for:

for (int i = 0; ...

и я заметил, что вы можете сделать то же самое в операторах if и switch:

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

switch (int ch = stream.get()) ...

Но когда я пытаюсь сделать то же самое в цикле while:

while ((int ch = stream.get()) != -1) ...

Компилятор (VС++ 9.0) совсем не нравится.

Это совместимое поведение? Есть ли причина для этого?

EDIT: Я нашел, что могу сделать это:

while (int ch = stream.get() != -1) ...

но из-за правил приоритета, которые интерпретируются как:

while (int ch = (stream.get() != -1)) ...

что я не хочу.

4b9b3361

Ответ 1

Грамматика для условия в стандарте '03 определяется следующим образом:

condition:
  expression
  type-specifier-seq declarator = assignment-expression

Таким образом, вышесказанное позволит допускать такие условия, как:

if ( i && j && k ) {}
if ( (i = j) ==0 ) {}
if ( int i = j ) {}

Стандарт позволяет условию объявлять переменную, однако они сделали это, добавив новое правило грамматики, называемое "условие", которое может быть выражением или декларатором с инициализатором. Результатом является то, что только потому, что вы находитесь в состоянии if, for, while или switch не означает, что вы можете объявить переменную внутри выражения.

Ответ 2

Это поведение не соответствует требованиям. Часть 6.5.1.2 стандартных состояний:

Когда условие оператора while является объявлением, объем объявляемой переменной расширяется от его пункта декларации (3.3.1) до конца оператора while. Оператор while формы

while (T t = x) statement

эквивалентно

label:
{ //start of condition scope
    T t = x;
    if (t) {
        statement
        goto label;
    }
}

Итак, в вашем примере ch должен быть объявлен в рамках цикла и корректно работать (при этом он воссоздается через каждую итерацию цикла). Причина наблюдаемого поведения, скорее всего, связана с тем, что компилятор не просматривал переменную правильно, а затем объявлял ее несколько раз.

Ответ 3

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

while() может иметь один из двух синтаксисов: while (<декларация>) или while (<выражение>). Объявление использует "=" и выглядит как выражение, но это другой синтаксический объект.

Когда вы пишете

while(int i = 1) {
}

это прекрасно. "int я = 1" - это объявление. Однако, что вы хотите,

while ( (int i = 1) + 3) {
}

Это совсем другое животное. Вы хотите выражение внутри while(), где одним из выражений выражения является объявление. Теперь объявление является выражением и, как таковое, не может быть частью выражения. Вот почему то, что вам нужно сделать, не может быть сделано.

(после написания всего разговора я заметил, что 2 других человека написали одно и то же. О, ну, тем более веселее.)

Ответ 4

Возможно, потому, что содержимое предложения while оценивается каждым циклом, поэтому он пытается несколько раз объявить "ch".

Примеры if, switch и for loop, которые вы указали, будут иметь "ch", которые будут определены только один раз.

Ответ 5

Вы можете поместить объявление переменной в тестовое выражение цикла while. То, что вы не можете сделать, это поместить оператор объявления в другие выражения. Например, в выражении a + b + c вы не можете заменить b на int i = f(). И то же самое для выражения (a); вы не можете вставить int i=f(), чтобы получить выражение (int i=f()).

Итак, в while (int i = foo()) самые внешние скобки являются частью оператора while, а не текстового выражения, и все законно. В while ((int i = foo())) самые внешние скобки все еще являются частью инструкции while. Тест-выражение будет иметь форму "(" expr ")", и вы получите синтаксическую ошибку.

Ответ 6

Попробуйте Это не работает

while (int ch = stream.get(), ch != -1) ...

Я никогда не пробовал, но если комментарий в вашем правильном правиле, это должно работать.
VS 2005 даже не компилирует его.