web-dev-qa-db-ja.com

条件ステートメントでのコンマの利点は何ですか?

ifステートメントは次のように記述できます。

if (a == 5, b == 6, ... , thisMustBeTrue)

if本文に入るには最後の条件のみが満たされる必要があります。

なぜそれが許可されていますか?

60
Abdul Rehman

あなたの例を少し変えて、これだと仮定して

_if ( a = f(5), b = f(6), ... , thisMustBeTrue(a, b) )
_

(_=_の代わりに_==_に注意してください)。この場合、コンマは左から右への評価の順序を保証します。で、これで

_if ( thisMustBeTrue(f(5), f(6)) )
_

f(5)f(6)の前に呼び出されるか後に呼び出されるかはわかりません。

より正式には、コンマを使用して、式_(a,b,c)_のsequenceを記述して、_;_を使用してステートメントのシーケンス_a; b; c;_。そしてちょうど_;_が シーケンスポイント (完全な表現の終わり)を作成するように、コンマも同様に作成します。評価の順序を制御するのはシーケンスポイントのみです。 this post を参照してください。

しかし、もちろん、この場合、あなたは実際にこれを書くでしょう

_a = f(5);
b = f(6);    
if ( thisMustBeTrue(a, b) )
_

では、コンマで区切られた式のシーケンスが_;_で区切られたステートメントのシーケンスよりも望ましいのはいつですか?私が言うことはほとんどありません。おそらく、マクロで、右側の置換を単一の式にしたい場合です。

67
Jon Jagger

要するに:そうすることは合法ですが、通常はifまたはwhileステートメントの条件部分でコンマ演算子を使用することは意味がありません(編集:後者は時々役立つかもしれませんがuser5534870が彼の答えで説明しています)。

より詳細な説明: CおよびC++では、構文関数(初期化子リスト、変数宣言、または関数呼び出し/宣言の要素の分離など)以外に、,も正常になります。 演算子例えば+であるため、式が許可されているすべての場所で使用できます(C++では、それをオーバーロードすることもできます)。
他のほとんどの演算子との違いは、両側が評価されますが、左と右の式の出力を決して結合せず、単に正しいものを返すことです。
誰か(おそらくDennis Ritchie)が何らかの理由で、通常は1つの式しか書けない位置に2つ(またはそれ以上)の無関係の式を書くために構文が必要だと判断したために導入されました。

現在、ifステートメントの条件は(とりわけ)そのような場所であり、そのため、そこで,演算子を使用することもできます-そうすることが理にかなっているかどうかはまったく異なる質問です!特に-とは異なります関数呼び出しまたは変数宣言-コンマは特別な意味を持たないため、常に行うことを行います。左右の式を評価しますが、右側の式の結果のみを返し、ifによって使用されます。ステートメント。

non-overloaded,- operatorを使用するのが理にかなっている、今考えることができる2つのポイントは次のとおりです。

  1. forループの先頭にある複数の反復子をインクリメントする場合:

    for ( ... ; ... ; ++i1, ++i2){
        *i2=*i1;
    }
    
  2. C++ 11 constexpr関数で複数の式を評価する場合。

これをもう一度繰り返すには:ifまたはwhileステートメントでカンマ演算子を使用する-例で示したように-実行するのは賢明なことではありません。これは、CおよびC++の言語構文でコードを記述できる別の例にすぎません。これは、一見すると期待するような動作をしません。他にもたくさんあります...

44
MikeMB

ifステートメントの場合、外部ではなくコンマ式に何かを入れることに実質的な意味はありません。

whileステートメントの場合、条件にコンマ式を指定すると、最初の部分eitherがループに入るとき、orがループするときに実行されます。コードの複製なしでは簡単に複製できません。

では、s do...whileステートメントはどうでしょうか。ループ自体を心配するだけですよね?ここでも、最初の部分をループに移動しても、コンマ式を安全に置換できないことがわかります。

まず、ループ本体の変数のデストラクタはまだ実行されていないため、違いが生じる可能性があります。また、ループ内のcontinueステートメントは、実際にループ本体ではなく条件内にある場合、コンマ式の最初の部分onlyに到達します。

15
user5534870

advantageはありません。コンマ演算子は、単に式リストの最後の式のタイプを持つ式であり、ifステートメントはブール式を評価します。

if(<expr>) { ... }
 with type of <expr> boolean

これは奇妙な演算子ですが、それは魔法ではありません-関数呼び出しで式のリストと引数リストを混同することを除いて。

foo(<args>)
 with <args> := [<expr>[, <expr>]*]

引数リストでは、コンマが引数の分離により強くバインドされることに注意してください。

10
BeyelerStudios

あなたがどれほどviousになりたいかにもよりますが、次は少しストレッチです。

参照またはポインターを介して渡されたパラメーターを変更することにより関数が値を返す状況を考えてみてください(おそらく設計が不適切なライブラリーから、または返された後に割り当てられないことでこの値が無視されないようにするため)。

void calculateValue(FooType &result) {/*...*/}

次に、resultに依存する条件ステートメントをどのように使用しますか?

変更する変数を宣言し、ifでチェックできます。

FooType result;
calculateValue(result);
if (result.isBared()) {
    //...
}

これは

FooType result;
if (calculateValue(result) , result.isBared()) {
    //...
}

それは本当に価値がありません。 ただしwhileループの場合、いくつかの小さな利点があります。結果がcalculateValue 'dでなくなるまでbarを呼び出す必要がある場合は、次のようにします。

FooType result;
calculateValue(result);  //[1] Duplicated code, see [2]
while (result.isBared()) {
    //... possibly many lines
    //separating the two places where result is modified and tested

    //How do you prevent someone coming after you and adds a `continue`
    //here which prevents result to be updated in the and of the loop?

    calculateValue(result); //[2] Duplicated code, see [1]
}

に凝縮することができます:

FooType result;
while (calculateValue(result) , result.isBared()) {
    //all your (possibly numerous) code lines go here
}

このようにresultを更新するコードは1か所にあり、その条件がチェックされる行の近くにあります。

おそらく無関係:変数をパラメーターの受け渡しで更新できるもう1つの理由は、計算された値を変更/返すことに加えて、関数がエラーコードを返す必要があることです。この場合:

ErrorType fallibleCalculation(FooType &result) {/*...*/}

それから

FooType result;
ErrorType error;

while (error = fallibleCalculation(result) , (Success==error && result.isBared())) {
    //...
}

しかし、コメントに記載されているように、カンマなしでもこれを行うことができます。

FooType result;
ErrorType error;

while (Success == fallibleCalculation(result) && result.isBared()) {
    //...
}
7
frozenkoi

まったくありません。そのコードのaの比較は完全に冗長です。

私の質問は、ifまたはwhileステートメントのコンマの利点は何ですか?なぜ許可されているのですか?

Cではステートメントと式が異なるため、存在します。複合expressionは、理論(および他のいくつかの言語)から理解され、コンマの形式で追加せずに欠落しています。 forステートメントでの使用は、彼らがそれを必要とした理由の最初の正当化でした。

しかし、健全な理論的観点から言語をより完全なものにすることで、誰も計画していなかった用途を後で見つけます。初期のC++は出力としてCを生成するトランスレータであり、インライン関数が実際に「インライン」を生成できるようにするには、シーケンシャルexpressionを持つことが絶対に不可欠でした。 Cコードのロジック。

これには、式が表示される任意の場所、を含むifステートメントの条件が含まれます。

同様に、「興味深い」マクロで使用されています。そして、C++がインライン関数を提供することでマクロを廃止したのと同じくらい、x11までのコンパイラーがBoost FOREACH範囲ループ(最終的にはx11で言語に追加された機能のエミュレーション)を非常に便利に見つけたので、コンマ演算子を含む悪魔のような巧妙なマクロのセット。

(うーん、現在のバージョンは、すべてを単一のifに詰め込むのではなく、連鎖else/whileを使用して複数のステートメントに展開します。)

現在、ステートメントを式(ラムダ)に入れる別の方法があるため、さらに新しい言語機能またはドメイン固有の埋め込み言語をエミュレートするマクロの将来のクレイジーなビジネスは、needもう使用しません。


ですから、そのようなコードを書かないでください。ヘルパー関数を記述したり、複数のステートメントに分割するよりも明確で単純な場合を除きます。

しかし、ある場所で簡単に使用したいのはマクロの場合だけで、その場所はifまたはwhileの括弧内にあります。それは、C++ソースコード内でホストされているドメイン固有言語、または(おそらく)埋め込みリアルで使用される例外処理の代替手段のような言語エミュレーション機能で正当化できます。時間システム。

つまり、通常の適切な使用法はありません。しかし、それは完全を期すためのものであり、誰かがいつそれが役立つと思うかは決してわかりません。

2
JDługosz