web-dev-qa-db-ja.com

do whileループの式の部分で変数を宣言できないのはなぜですか?

次の構文が有効です。

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宣言子braced-init-list

2条件の規則は、selection-statementsforおよびwhileステートメントの両方に適用されます(6.5)。 [...]

およびセクション6.5

1反復ステートメントはループを指定します。

iteration-statement:whileconditionstatementdoステートメントwhile);

代わりに、次のような醜いことをする必要があります。

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

これの理論的根拠は何ですか?

33
user4351360

スコープが問題になるようですが、do whileステートメントのi部分で宣言されたwhileのスコープは何でしょうか?宣言が実際にループ自体の下にあるときに、ループ内で変数を使用できるようにするのはかなり不自然に思えます。宣言はループの本体の前にあるため、他のループではこの問題は発生しません。

ドラフト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 それは(emphasis mine)と言っています:

Doステートメントでは、式の値がfalseになるまで、サブステートメントが繰り返し実行されます。 テストはステートメントの各実行後に行われます。

つまり、宣言に到達する前に、ループの本体が評価されます。

この場合の例外を作成することはできますが、一般に名前の宣言のポイントは、完全な宣言(クラスメンバー変数などのいくつかの例外を除く)を確認した後であるという直感に違反します。不明確な利点。 宣言のポイントはセクション3.3.2でカバーされています。

38
Shafik Yaghmour

許可するのが難しい理由はいくつかあります。

言語は、すべてを宣言する必要があるという一般的な規則に固執します上記使用ポイント。この場合、do-whileで宣言された変数は、以下予想される自然なスコープ(サイクル本体)として宣言されます。サイクル内でこの変数にアクセスできるようにするには、do-whileサイクルに特別な処理が必要でした。そのような特別な扱いの例を知っていても(たとえば、クラス内のメンバー関数本体は、宣言されたものを含むすべてのクラスメンバーを見ることができます以下)、do-whileサイクルでそれを行うことにはおそらくあまり実用的な意味がありません。

do-whileの場合、これらの特別な処理ルールでは、この方法で宣言された変数の初期化を処理する意味のある方法を見つける必要もあります。 C++言語では、このような変数の有効期間はループの1回の反復に制限されていることに注意してください。つまり、変数は反復ごとに作成および破棄されます。つまり、do-whileサイクルでは、ループ本体のbeginningに初期化を移動するルールを導入しない限り、変数は常に初期化されないままになります。それは私の意見ではかなり混乱するでしょう。

20
AnT

ブロックの後にiの宣言をして、ブロック内でそれにアクセスできるようにするのは非常に不自然です。 forwhileの宣言は、ループロジックで必要な変数に限定されたスコープの使用を与える優れた省略形です。

このようにするためのクリーナー:

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

これは、他のすべてが、変数を使用する前に変数を宣言する慣行に従っているためです。例:

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は、変数を宣言する意味がありません。スコープが終了すると同時に、そのブロックが終了するためにチェックされるためです。

5
davidahines

これを追加

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

コードの最初に。

今、あなたは書くことができます

do (int i = get_data()) 
{

    // your code

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

これが重要です#defineは、do-whileループでdoキーワードの元の構文を壊しません。

しかし、私はそれがあいまいであることを認めます。

0
DaBler