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

Why can't you declare a variable inside the expression portion of a do while loop?

本文关键字:声明 变量 一个 do 不能 while 循环 表达式部 为什么      更新时间:2023-10-16

以下语法有效:

while (int i = get_data())
{
}

但以下不是:

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

我们可以通过标准草案N4140 6.4节了解原因:

1 [...]

条件表达属性-说明符-seqoptdecl-specifier-seq declarator = initializer-clauseattribute-specifier-seqoptdecl-specifier-seq declarator braced-init-list

2 条件规则既适用于选择语句,也适用于 到forwhile声明(6.5(。[...]

和第 6.5

1 迭代语句指定循环。

迭代语句:              while(条件(语句              do语句while (表达式( ; 

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

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

这样做的理由是什么?

似乎范围

将是问题所在,在do while语句的while部分中声明i的范围是什么?当声明实际上位于循环本身下方时,在循环中有一个可用的变量似乎很不自然。其他循环没有此问题,因为声明位于循环主体之前。

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

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指出的那样,如果我们看一下第[stmt.do]p2节,它说(强调我的(:

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

这意味着在我们到达声明之前就对循环的主体进行了评估。

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

有几个

原因可以解释为什么很难允许。

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

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

块之后声明i然后能够在块中访问它是非常不自然的。forwhile 中的声明是很好的简写,它们对循环逻辑中所需的变量进行有限范围的使用。

这样做更干净:

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
}

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

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

添加这个

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

在代码的开头。

现在,你可以写

do (int i = get_data()) 
{
    // your code
} while ((i = get_data()));

重要的是,此#define不会破坏 do-while 循环中 do 关键字的原始语法。

但是,我承认这是晦涩难懂的。

您的第一个语法有效,而第二个语法无效。但是,您的 while 循环将永远循环,即使您的函数 get_data(( 返回 0。不确定这是否正是您想要发生的事情。