andのシンタックスシュガーとして使用された「非常に悪いこと」はありますか?&&=
||=
bool foo = foo && bar
bool foo = foo || bar
3 に答える
Aは、C++ でbool
のみtrue
orにすることができます。false
そのため、&=
andを使用すること|=
は比較的安全です (ただし、この表記法は特に好きではありません)。確かに、それらは論理演算ではなくビット演算を実行します (したがって、短絡しません) が、これらのビット演算は明確に定義されたマッピングに従います。これは、両方のオペランドが型である限りbool
、論理演算と事実上同等です。 . 1
他の人がここで言ったことに反してbool
、C++ の a は、 のような異なる値を持つことはできません2
。その値を に代入すると、標準に従ってbool
に変換されます。true
無効な値を a に取得する唯一の方法は、 on ポインターbool
を使用することです。reinterpret_cast
int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
しかし、このコードはとにかく未定義の動作を引き起こすため、C++ コードに準拠する際にこの潜在的な問題を安全に無視することができます。
1確かに、Angew のコメントが示すように、これはかなり大きな警告です。
bool b = true;
b &= 2; // yields `false`.
その理由はb & 2
、式が と同等になるように が整数昇格を実行しstatic_cast<int>(b) & 2
、結果が になり0
、それが に変換されるためbool
です。operator &&=
したがって、 an の存在によって型安全性が向上することは事実です。
&&
と&
はセマンティクスが異なります。&&
最初のオペランドが の場合、 は 2 番目のオペランドを評価しませんfalse
。つまり、次のようなもの
flag = (ptr != NULL) && (ptr->member > 3);
安全ですが、
flag = (ptr != NULL) & (ptr->member > 3);
ではありませんが、両方のオペランドの型はbool
です。
&=
とについても同様です|=
。
flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
以下とは異なる動作をします。
flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
簡潔な答え
すべての演算子+=
, -=
, *=
, /=
, &=
, |=
... は算術演算であり、同じ期待値を提供します。
x &= foo() // We expect foo() be called whatever the value of x
ただし、演算子&&=
およびは論理的であり、多くの開発者はが常に で呼び出される||=
ことを期待しているため、これらの演算子はエラーが発生しやすい可能性があります。foo()
x &&= foo()
bool x;
// ...
x &&= foo(); // Many developers might be confused
x = x && foo(); // Still confusing but correct
x = x ? foo() : x; // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo(); // Obvious
のショートカットを取得するために、C/C++ をさらに複雑にする必要があるの
x = x && foo()
でしょうか。不可解なステートメントをもっと難読化したい
x = x && foo()
ですか?
それとも、次のような意味のあるコードを書きたいif (x) x = foo();
ですか?
長い答え
例&&=
オペレーターが利用可能な場合&&=
、次のコード:
bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value
次と同等です。
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
この最初のコードは、多くの開発者が戻り値が何であれ常に呼び出されると考えているため、エラーが発生しやすくなっています。が返されたときだけ呼び出される場所を書くようなものです。f2()
f1()
bool ok = f1() && f2();
f2()
f1()
true
- 開発者が実際に return の場合に
f2()
のみ呼び出されることを望んでいる場合、上記の 2 番目のコードはエラーが発生しにくくなりますf1()
。true
f2()
それ以外の場合 (開発者は常に呼び出されることを望んでいます)、&=
十分です:
例&=
bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
さらに、コンパイラーは、以下のコードよりも上のコードを最適化する方が簡単です。
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
比較&&
して&
&&
演算子とを値&
に適用したときに同じ結果が得られるかどうか疑問に思うかもしれません。bool
次の C++ コードを使用して確認してみましょう。
#include <iostream>
void test (int testnumber, bool a, bool b)
{
std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
"a && b = "<< (a && b) <<"\n"
"a & b = "<< (a & b) <<"\n"
"======================" "\n";
}
int main ()
{
test (1, true, true);
test (2, true, false);
test (3, false, false);
test (4, false, true);
}
出力:
1) a=1 and b=1
a && b = 1
a & b = 1
======================
2) a=1 and b=0
a && b = 0
a & b = 0
======================
3) a=0 and b=0
a && b = 0
a & b = 0
======================
4) a=0 and b=1
a && b = 0
a & b = 0
======================
結論
したがって、はい&&
、&
for の値に置き換えることができbool
ます ;-)
したがって、&=
の代わりに使用することをお勧めします&&=
。ブール値には役に立たない
と考えることができます。&&=
同じ||=
演算子
|=
は、よりもエラーが発生しにくい||=
開発者が、次の代わりに、 return の場合にf2()
のみ呼び出されることを希望する場合:f1()
false
bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...
次のよりわかりやすい代替案をお勧めします。
bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)
または、すべてを 1 つの線のスタイルにしたい場合:
// this comment is required to explain to developers that
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();