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

следующий синтаксис:

while (int i = get_data())
{
}

но это не так:

do
{
} while (int i = get_data());

мы можем увидеть почему через проект стандарта:

[N4140/6.4]

1 [...]

condition:
     expression
     attribute-specifier-seqoptdecl-specifier-seq declarator = initializer-clause
     attribute-specifier-seqoptdecl-specifier-seq declarator braced-init-list

2 правила для условий применяются как к selection-заявления и к for и while заявления (6.5). [...]

[N4140/6.5]

1 итерации операторы задают цикл.

      iteration-statement: 
             while ( condition ) statement
             do statement while ( expression ) ;

вместо этого, вы вынуждены делать что-то уродливое, как:

int i = get_data();
do
{
} while ((i = get_data())); // double parentheses sic

каково обоснование этого?

6 ответов


похоже, что определение области будет проблемой, какова будет область i объявлен в while часть do while заявление? Казалось бы, довольно неестественно иметь переменную, доступную в цикле, когда объявление фактически ниже самого цикла. У вас нет этой проблемы с другими циклами, так как объявления приходят перед телом цикла.

если мы посмотрим на проект стандарта C++ мы видим из раздела 6.5.1 в пока заявление, что для в то время как заявление что:

while (T t = x) statement

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

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

и:

переменной в условии уничтожается и создается с каждой итерации цикла.

как бы мы сформулировали это для do while случае?

и, как указывает cdhowie, если мы посмотрим на раздел 6.5.2 заявление do он говорит (акцент шахта):

в инструкции do подстанция выполняется повторно до тех пор, пока значение выражения становится false. испытание происходит после каждого исполнение заявления.

что означает, что тело цикла оценивается до того, как мы даже достигнем объявления.

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


есть несколько причин, почему это было бы трудно допустить.

язык придерживается общего правила, что все должно быть объявлено выше точки использования. В этом случае переменная, объявленная в do-while будет объявлен ниже свой предполагаемый естественный объем (тело цикла). Сделать эту переменную доступной внутри цикла потребовало бы специальной обработки для do-while циклы. Хотя мы знаем примеры таких специальных обработка (например, тела функций-членов в классе могут видеть все члены класса, включая объявленные ниже), вероятно, нет большого практического смысла делать это для do-while циклы.

в случае do-while эти правила специального режима также потребуют поиска значимого способа обработки инициализации переменных, объявленных таким образом. Обратите внимание, что в языке C++ время жизни такой переменной ограничивается одной итерации цикла, т. е. переменная создается и уничтожается на каждой итерации. Это означает, что для do-while цикл переменная всегда будет оставаться неинициализированной, если вы не введете какое-то правило, которое каким-то образом переместит инициализацию в начало тела цикла. На мой взгляд, это было бы довольно запутанно.


было бы очень неестественно иметь заявление i после блока, а затем иметь доступ к нему в блоке. Объявление в for и while хорошие короткие руки, которые дают ограниченное использование переменной, которая необходима в логике цикла.

чище сделать это таким образом:

int i;
do {
  i = get_data();
  // whatever you want to do with i;
} while (i != 0);

это потому, что все остальное следует практике объявления переменных перед их использованием, например:

public static void main(String[] args){ 
  // scope of args
}

for(int i=1; i<10; i++){
  // scope of i
}


{
...
int somevar;
//begin scope of var

...

//end of scope of var
}

это потому, что вещи анализируются сверху вниз, и потому, что после этого соглашения вещи интуитивно понятны, поэтому вы можете объявить некоторое время(int var

do while не имеет никакого смысла объявлять переменную, потому что область закончится одновременно это будет проверено, потому что именно тогда этот блок будет завершен.


добавить

#define do(cond) switch (cond) do default:

в начале вашего кода.

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

do (int i = get_data()) 
{

    // your code

} while ((i = get_data()));

важно, чтобы это #define не нарушает исходный синтаксис do ключевое слово в цикле do-while.

однако я признаю, что это неясно.


ваш первый синтаксис действителен, а второй нет. Однако, ваш цикл while будет повторяться вечно, даже если ваша функция get_data() возвращает 0. Не уверен, что это именно то, чего ты хочешь.