以下语法有效:
while (int i = get_data())
{
}
但以下不是:
do
{
} while (int i = get_data());
我们可以通过草案标准N4140
部分 6.4 了解原因:
1 [...]
condition: expression attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list2条件规则适用于 selection-statements 和 到
for
和while
语句(6.5)。 [...]
和 6.5
部分相反,你被迫做一些丑陋的事情:1迭代语句指定循环。
iteration-statement:while
( condition ) statementdo
statementwhile
( expression ) ;
int i = get_data();
do
{
} while ((i = get_data())); // double parentheses sic
这是什么原因?
答案 0 :(得分:38)
似乎范围界定是问题,在i
声明的while
部分中声明的do while
范围是什么?当声明实际上在循环本身之下时,在循环内有一个变量可能看起来相当不自然。由于声明位于循环体之前,因此其他循环没有这个问题。
如果我们查看draft C++ standard部分[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语句中,重复执行子语句直到 表达式的值变为false。 测试在每次之后进行 执行声明。
这意味着在我们甚至达到声明之前评估循环体。
虽然我们可以为这种情况创建一个例外,但它违反了我们的直觉,即一般来说,在我们看到完整的声明之后,声明的声明点(有一些例外的类成员变量)效益不明确。 声明点将在3.3.2
部分中介绍。
答案 1 :(得分:20)
有几个原因导致难以允许。
该语言坚持一般规则,即所有内容都应在上面使用。在这种情况下,do-while
中声明的变量将在下面声明其预期的自然范围(循环体)。在循环内部访问此变量将需要对do-while
个循环进行特殊处理。尽管我们知道这种特殊处理的例子(例如,类内成员函数体可以看到所有类成员,包括在下面声明的那些成员),但对于{{1}这样做可能没什么实际意义。周期。
在do-while
的情况下,这些特殊处理规则还需要找到一种有意义的方法来处理以这种方式声明的变量的初始化。注意,在C ++语言中,这种变量的生命周期限于循环的一次迭代,即在每次迭代时创建和销毁变量。这意味着对于do-while
循环,变量将始终保持未初始化,除非您引入一些规则,以某种方式将初始化移动到循环体的开始。在我看来,那会非常混乱。
答案 2 :(得分:8)
在块之后声明i
然后能够在块中访问它将是非常不自然的。 for
和while
中的声明是很好的短手,可以将有限范围的使用用于循环逻辑中所需的变量。
以这种方式清洁:
int i;
do {
i = get_data();
// whatever you want to do with i;
} while (i != 0);
答案 3 :(得分: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
}
这是因为事情是自上而下解析的,因为遵循这个约定使事情保持直观,因此你可以声明一个while(int var&lt; 10),因为该var的范围将是循环内的区域,之后声明。
do while没有任何意义来声明一个变量,因为范围将在检查时同时结束,因为当该块完成时它就会结束。
答案 4 :(得分:0)
添加此
#define do(cond) switch (cond) do default:
在代码的开头。
现在,你可以写
do (int i = get_data())
{
// your code
} while ((i = get_data()));
重要的是,此#define
不会破坏do-while循环中do
关键字的原始语法。
但是,我承认这是模糊不清的。
答案 5 :(得分:-2)
您的第一个语法有效,而第二个语法无效。 但是,即使函数get_data()返回0,你的while循环也将永远循环。 不确定这是不是你想要发生的事情。