为什么不能在do while循环的表达式部分中声明变量?

use*_*360 32 c++ declaration do-while

以下语法有效:

while (int i = get_data())
{
}
Run Code Online (Sandbox Code Playgroud)

但以下不是:

do
{
} while (int i = get_data());
Run Code Online (Sandbox Code Playgroud)

我们可以通过标准草案N41406.4节了解原因:

1 [...]

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

2条件规则既适用于选择陈述,也适用于forwhile陈述(6.5).[...]

和第6.5

1迭代语句指定循环.

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

相反,你被迫做一些丑陋的事情:

int i = get_data();
do
{
} while ((i = get_data())); // double parentheses sic
Run Code Online (Sandbox Code Playgroud)

这是什么理由?

Sha*_*our 38

似乎范围界定是问题,在i声明的while部分中do while声明的范围是什么?当声明实际上在循环本身之下时,在循环内有一个变量可能看起来相当不自然.由于声明位于循环体之前,因此其他循环没有此问题.

如果我们查看草案C++标准部分[stmt.while] p2,我们会看到while语句:

while (T t = x) statement
Run Code Online (Sandbox Code Playgroud)

相当于:

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

和:

在条件中创建的变量将被销毁,并在循环的每次迭代中创建.

我们如何为do while此案制定此案?

正如cdhowie所指出的那样,如果我们看一下[stmt.do] p2部分(强调我的话):

在do语句中,重复执行子语句,直到表达式的值变为false.测试在每次执行语句后进行.

这意味着在我们甚至达到声明之前评估循环体.

虽然我们可以为这种情况创建一个例外,但它违反了我们的直觉,即一般来说,名称的声明点是在我们看到完整的声明(例如类成员变量的例外情况)之后具有不明确的好处.声明的内容将在章节中介绍3.3.2.

  • (特别是因为do ... while循环的主体在条件被评估之前执行了一次,所以将一个声明,尤其是具有赋值的声明放入循环条件中确实没有任何意义.) (14认同)
  • @πάνταῥεῖ我认为答案更多的是关于变量声明如何在它有效的循环体之后变得没有意义,而不是任何可能的阴影. (2认同)

AnT*_*AnT 20

有几个原因导致难以允许.

该语言坚持一般规则,即所有内容都应在使用点之上声明.在这种情况下,声明的变量do-while将被声明为低于其预期的自然范围(循环体).在循环中使这个变量可访问将需要对do-while循环进行特殊处理.即使我们知道这种特殊处理的例子(例如,类内成员函数体可以看到所有类成员,包括下面声明的那些成员),但在do-while循环中这样做可能没有多少实际意义.

do-while这些特殊处理规则的情况下,还需要找到一种有意义的方法来处理以这种方式声明的变量的初始化.请注意,在C++语言中,此类变量的生命周期仅限于循环的一次迭代,即在每次迭代时创建和销毁变量.这意味着对于do-while循环,变量将始终保持未初始化,除非您引入一些规则,以某种方式将初始化移动到循环体的开头.在我看来,那将是相当混乱的.


sfj*_*jac 8

i在块之后声明并且然后能够在块中访问它将是非常不自然的.声明for并且while是很好的短手,可以为循环逻辑中需要的变量提供有限范围的使用.

清洁这样做:

int i;
do {
  i = get_data();
  // whatever you want to do with i;
} while (i != 0);
Run Code Online (Sandbox Code Playgroud)


dav*_*nes 5

这是因为其他一切都遵循在使用它们之前声明变量的做法,例如:

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
}
Run Code Online (Sandbox Code Playgroud)

这是因为事情是自上而下解析的,因为遵循这个约定使事情保持直观,因此你可以声明一个while(int var <10),因为在声明之后,var的范围将是循环内的区域.

do while对于声明变量没有任何意义,因为范围将在检查的同时结束,因为那是在该块完成时.