133

何が起きてる?

if(int a = Func1())
{
    // Works.
}

if((int a = Func1()))
{
    // Fails to compile.
}

if((int a = Func1())
    && (int b = Func2()))
)
{
    // Do stuff with a and b.
    // This is what I'd really like to be able to do.
}

2003 規格のセクション 6.4.3 では、選択ステートメントの条件で宣言された変数が、条件によって制御されるサブステートメントの末尾まで拡張されるスコープを持つ方法について説明しています。しかし、宣言の周りに括弧を入れることができないことや、条件ごとに宣言が 1 つしかないことについて何も言っていないところがわかりません。

この制限は、条件で 1 つの宣言のみが必要な場合でも煩わしいものです。このことを考慮。

bool a = false, b = true;

if(bool x = a || b)
{

}

x を false に設定して 'if'-body スコープに入りたい場合は、宣言に括弧が必要です (代入演算子は論理 OR よりも優先順位が低いため)。ただし、括弧を使用できないため、外側で x を宣言する必要があります。その宣言を、必要以上の範囲にリークします。明らかにこの例は簡単ですが、より現実的なケースは、a と b がテストする必要がある値を返す関数である場合です。

それで、私がやりたいことは標準に準拠していないのでしょうか、それともコンパイラが私のボールを壊しているだけですか(VS2008)?

4

8 に答える 8

113

あなたはすでに問題をほのめかしていると思います。コンパイラはこのコードで何をすべきでしょうか?

if (!((1 == 0) && (bool a = false))) {
    // what is "a" initialized to?

「&&」演算子は短絡論理積です。つまり、最初の部分(1==0)が偽であることが判明した場合(bool a = false)、最終的な答えが偽であることが既にわかっているため、2 番目の部分は評価されるべきではありません。が評価されない場合(bool a = false)、後で を使用するコードをどうするaか? 変数を初期化せずに未定義のままにしますか? デフォルトに初期化しますか?データ型がクラスであり、これを行うと望ましくない副作用がある場合はどうなるでしょうか? 代わりにクラスを使用し、ユーザーがパラメーターを提供する必要boolがあるようなデフォルトのコンストラクターがなかったとしたら、どうすればよいでしょうか?

別の例を次に示します。

class Test {
public:
    // note that no default constructor is provided and user MUST
    // provide some value for parameter "p"
    Test(int p);
}

if (!((1 == 0) && (Test a = Test(5)))) {
    // now what do we do?!  what is "a" set to?

あなたが見つけた制限は完全に合理的であるように思われます - それはこの種のあいまいさが起こらないようにします.

于 2011-10-20T13:50:05.800 に答える
99

iforwhileステートメントの条件は、、または単一の変数宣言(初期化あり)のいずれかです。

宣言は式の一部を形成できないため、2番目と3番目の例は有効な式でも有効な宣言でもありません。3番目の例のようなコードを記述できると便利ですが、言語構文を大幅に変更する必要があります。

宣言の前後に括弧を付けられないことについては何も書かれておらず、条件ごとに1つの宣言だけについても何も書かれていません。

6.4 / 1の構文仕様では、条件について次のようになっています。

condition:
    expression
    type-specifier-seq declarator = assignment-expression

括弧やその他の装飾を使用せずに、単一の宣言を指定します。

于 2011-10-20T14:01:09.200 に答える
23

より狭いスコープで変数を囲みたい場合は、いつでも追加で使用できます{ }

//just use { and }
{
    bool a = false, b = true;

    if(bool x = a || b)
    {
        //...
    }
}//a and b are out of scope
于 2011-10-20T14:12:27.417 に答える
18

最後のセクションはすでに機能しています。少し異なる方法で記述する必要があります。

if (int a = Func1())
{
   if (int b = Func2())
   {
        // do stuff with a and b
   }
}
于 2011-10-20T16:38:40.547 に答える
2

ループを使用した醜い回避策を次に示します (両方の変数が整数の場合)。

#include <iostream>

int func1()
{
    return 4;
}

int func2()
{
    return 23;
}

int main()
{
    for (int a = func1(), b = func2(), i = 0;
        i == 0 && a && b; i++)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }

    return 0;
}

しかし、これは他のプログラマーを混乱させ、かなり悪いコードなので、お勧めしません。

単純な囲み{}ブロック (既に推奨されている) の方がはるかに読みやすい:

{
    int a = func1();
    int b = func2();

    if (a && b)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }
}
于 2015-06-06T15:52:46.707 に答える
1

注意すべきことの 1 つは、より大きな if ブロック内の式が

if (!((1 == 0) && (bool a = false)))

必ずしも左から右に評価されるとは限りません。私が当時持っていたやや微妙なバグの 1 つは、コンパイラが実際には左から右ではなく右から左をテストしていたという事実に関係していました。

于 2011-10-25T19:45:41.513 に答える