34

tl; dr:C ++に非短絡論理積がありますか(&&と同様)?

呼び出したい関数が2つあり、戻り値を使用して3番目の複合関数の戻り値を計算します。問題は、両方の関数に常に評価してもらいたいということです(システムの状態に関するログ情報を出力するため)

IE:

bool Func1(int x, int y){
  if( x > y){
    cout << "ERROR- X > Y" << endl;
  }
}
bool Func2(int z, int q){
  if( q * 3 < z){
    cout << "ERROR- Q < Z/3" << endl;
  }
}
bool Func3(int x, int y, int z, int q){
  return ( Func1(x, y) && Func2(z, q) );
}

もちろん、関数の条件はそれほど単純ではありません。そうです、一時変数を使用して2つの関数の戻り値を格納し、一時変数に対して「短絡」ロジックを実行できることに気付きましたが、両方の関数からログメッセージを取得しながら、Func3で1行の戻り値を維持するための、「エレガントな」言語ソリューションがあるかどうか疑問に思いました。


回答の概要:

「ビットごとの」演算子| および&を使用して効果を得ることができますが、returnタイプがboolの場合に限ります。ANSIC++仕様ではこれについての言及は見つかりませんでした。私の知る限り、これは「bool」がint(true = 1、false = 0)に変換され、次にビット演算子が使用されてから、boolに変換されるために機能します。

演算子「+」および「*」も使用できます。これはANSIC++仕様には記載されていませんが、おそらく上記と同じ理由で機能します。+trueは1に変換され、0以外はtrueに変換されるため、 ""give"または" 。*1(true)* 0(false)== 0(false)および1(true)* 1(true)== 1(true)であるため、""は"および"に対して機能します

これらは両方とも、整数への暗黙の型変換に依存しているようで、その後ブール値に戻ります。これらは両方とも、コードを維持しようとする人を台無しにする可能性があります。

他の回答は、「一時的なものを使用する」または「独自に実装する」に要約されますが、これは問題ではありませんでした。目標は、それを実行するためにC++標準に実装されたオペレーターがすでに存在するかどうかを確認することでした。

4

7 に答える 7

37

&演算子は、オペランドに対して論理「and」演算を実行し、短絡boolされません。

シーケンスポイントではありません。オペランドの評価の順序に依存することはできません。ただし、両方のオペランドが評価されることが保証されています。

これを行うことはお勧めしません。一時変数を使用することは、より良い解決策です。「賢いコード」の可読性を犠牲にしないでください。

于 2009-11-18T19:55:07.547 に答える
23

はい、一時変数を使用して2つの関数の戻り値を格納し、一時変数に対して「短絡」ロジックを実行できることに気付きましたが、それを維持するための「エレガントな」言語ソリューションがあるかどうか疑問に思いました。両方の関数からログメッセージを取得しながら、Func3で1行戻ります。

それが「エレガントな」解決策になります:)。評価順序の副作用に依存することは、エレガントでエラーが発生しやすいとは言えず、プロジェクトに迷い込んだ次の開発者にとっては理解しにくいでしょう。もちろん、副作用に依存することは、次のスニペットのようなものとは対照的です。これは、評価順序のみに依存するための完全に論理的で有効なユースケースです。

if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }
于 2009-11-18T19:54:38.167 に答える
14

はい、これを行うための組み込み演算子があります。 +非短絡ORを*実行し、ANDを実行します。

☺</h1>

#include <iostream>
using namespace std;

void print(bool b)
{
    cout << boolalpha << b << endl;
}

int main() 
{
    print(true + false);
    print(true * false);
}

出力:

true

false

于 2009-11-18T20:45:05.913 に答える
4

あなたは簡単にあなた自身を書くことができます。

bool LongCircuitAnd( bool term1, bool term2 ) { return term1 && term2; }

bool Func3(int x, int y, int z, int q){
  return LongCircuitAnd( Func1(x,y), Func2(z,q) ); 

そして、あなたが非常に空想になりたいなら、あなたはそれをインライン化することさえできます!!!

さて、さて、もしあなたが本当に関数を呼び出すことのひどいオーバーヘッドを望まないのなら。

bool Func3(int x, int y, int z, int q){
  return ((int)Func1(x,y)) * ((int)Func2(z,q)); 

しかし、私はそれがエレガントだとは思いません。過度にスマートなコンパイラがこれを短絡させる可能性があると考えられます...

于 2009-11-18T20:03:10.637 に答える
3

一時変数を使用したいが、単一のステートメントに戻る場合は、コンマ演算子を使用できます。

return (b1=Func1()), (b2=Func2()), (b1&&b2);

コンマ演算子はシーケンスポイントを強制するため、各演算子は左側のオペランドを評価し、結果を破棄してから、右側のオペランドを評価します。

もう1つの可能性は、私がお勧めしがちなことですが、2つの関数が「&&」演算子をオーバーロードする型を返すことです。オーバーロードされた演算子は関数を呼び出すため、組み込み演算子が呼び出されない場合でも(&&のように)、常に両方のオペランドを評価します。通常、これは問題ですが、この場合はまさに必要なものです。

class mybool { 
    bool value;
public:
    bool operator&&(mybool const &other) const { 
        return value && other.value;
    }
};

mybool Func1(int, int);
mybool Func2(int, int);

bool Func3(int x, int y, int z, int q) { 
    return Func1(x, y) && Func2(z,q);
}

これは機能しますが、少し「賢い」ように思えます。これは、ほとんどの読者にはまったくわかりません。別の名前myboolが役立つかもしれませんが、冗長にならずに意図をうまく反映している名前は、正味の損失になるとは思えません。

于 2009-11-18T20:34:45.690 に答える
2

はい。のオーバーロードされたバージョンは短絡しません—左側のオペランドが結果を「決定」する場合でも、両方のオペランドを評価します... operator&&ソースoperator||

そうは言っても、オーバーロードしないでoperator&&くださいoperator||。短絡を確認したり、短絡したと想定し&&たりするメンテナンスプログラマーに親切にしてください。||

于 2009-11-18T20:28:09.473 に答える
2

ほぼ普遍的であるが、しばしば文書化されていない非標準演算子がまさにこの目的のために導入され、GCCによって開拓されx ?: y(ゼロ以外の場合はx、それ以外の場合はy)、現在は悲しいことに削除され>?<?最小/最大演算子とそれらの複合割り当てフォーム(httpを参照) ://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html)。悲しいことに、&すでに&&使用されているので、適切な文字シーケンスを見つけるためにバレルの底を削っていたようですが、それは私の意見です-これが選択された理由についての歴史的な説明を歓迎します。

そのため、現在、他の多くの演算子ほどよく知られていませんが>!演算子(適切に、しかし退屈に「長回路と」と呼ばれますが、知識のある人には口語的に「より大きな結び目」)がほとんどのCおよびC ++コンパイラによって追加されました(この要件を満たすためのGCCおよびMSVC++):

bool f1() { ... }
bool f2() { ... }

...
bool f3() { return f1() >! f2(); }

スピンのためにそれを取ってください;-)。

于 2011-04-07T08:08:31.703 に答える