Why doesn't c++ have &&= or ||= for booleans?

前端 未结 3 684
醉酒成梦
醉酒成梦 2020-12-02 13:00

Is there a "very bad thing" that can happen &&= and ||= were used as syntactic sugar for bool foo = foo && bar

3条回答
  •  [愿得一人]
    2020-12-02 13:20

    Short answer

    All the operators +=, -=, *=, /=, &=, |=... are arithmetic and provide same expectation:

    x &= foo()  // We expect foo() be called whatever the value of x
    

    However, operators &&= and ||= would be logical, and these operators might be error-prone because many developers would expect foo() be always called in 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
    
    • Do we really need to make C/C++ even more complex to get a shortcut for x = x && foo()?

    • Do we really want to obfuscate more the cryptic statement x = x && foo()?
      Or do we want to write meaningful code like if (x) x = foo();?


    Long answer

    Example for &&=

    If &&= operator was available, then this code:

    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
    

    is equivalent to:

    bool ok = true;
    if (ok) ok = f1();
    if (ok) ok = f2(); //f2() is called only when f1() returns true
    

    This first code is error-prone because many developers would think f2() is always called whatever the f1() returned value. It is like writing bool ok = f1() && f2(); where f2() is called only when f1() returns true.

    • If the developer actually wants f2() to be called only when f1() returns true, therefore the second code above is less error-prone.
    • Else (the developer wants f2() to be always called), &= is sufficient:

    Example for &=

    bool ok = true;
    ok &= f1();
    ok &= f2(); //f2() always called whatever the f1() returned value
    

    Moreover, it is easier for compiler to optimize this above code than that below one:

    bool ok = true;
    if (!f1())  ok = false;
    if (!f2())  ok = false;  //f2() always called
    

    Compare && and &

    We may wonder whether the operators && and & give the same result when applied on bool values?

    Let's check using the following C++ code:

    #include 
    
    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);
    }
    

    Output:

    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
    ======================
    

    Conclusion

    Therefore YES we can replace && by & for bool values ;-)
    So better use &= instead of &&=.
    We can consider &&= as useless for booleans.

    Same for ||=

    operator |= is also less error-prone than ||=

    If a developer wants f2() be called only when f1() returns false, instead of:

    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 ...
    

    I advice the following more understandable alternative:

    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)
    

    or if you prefer all in one line style:

    // 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();
    

提交回复
热议问题