36

tl;dr: Is there a non-short circuit logical AND in C++ (similar to &&)?

I've got 2 functions that I want to call, and use the return values to figure out the return value of a 3rd composite function. The issue is that I always want both functions to evaluate (as they output log information about the state of the system)

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

Of course, the conditionals aren't quite that simple in the functions, and yes, I realize that I could use temporary variables to store the returns of the two functions and then do the "short-circuit" logic on the temporary variables, but I was wondering if there was an "elegant" language solution to keep the one-line return in Func3 while still getting the logging messages from both functions.


Summary of responses:

The "bitwise" operators | and & can be used to get the effect, but only if the return type is bool. I found no mention of this in the ANSI C++ spec. From what I can tell, this works because the "bool" is converted to an int (true = 1, false = 0), and then the bitwise operator is used, then it is converted back to a bool.

The Operators "+" and "*" can also be used. This is not mentioned in the ANSI C++ Spec, but probably works because of the same reason as above. "+" give "or" because true is converted to 1, and then anything other than 0 is converted back to true. "*" works for "and" because 1 (true) * 0 (false) == 0(false) and 1(true) * 1(true) == 1(true)

Both of these seem to rely on implicit type conversion to integer and then back to bool. Both of these will likely mess up whomever tries to maintain the code.

Other responses boil down to "Just use temporaries" or "Implement your own" which was not the question. The goal was to see if there was already an operator implemented in the C++ standard to do it.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
Luciano
  • 1,571
  • 3
  • 17
  • 23
  • 4
    I would just use the temporaries. It's at least as clear as calling the functions inside the if() and you don't have to look for obscure ways to get your method to work. – Ron Warholic Nov 18 '09 at 19:56
  • "elegant: displaying effortless beauty and simplicity in movement or execution" If a temporary variable is effortless (to both write and understand) and simply achieves your goal, is it elegant? –  Nov 18 '09 at 20:25
  • I think you can just use temporary volatile variables as in: `volatile uchar retVal1 = Func1(); volatile uchar retVal2 = Func2(); if(retVal1 && retVal2) { // Do my stuff } ` This makes sure that the program evaluates both variables (aka calls both functions), and hence you can use those in your condition. – davidanderle Oct 31 '18 at 15:00
  • @davidanderle, volatile is not needed. Func1() and Func2() will be called anyway. – Alex Che Dec 04 '20 at 15:58

7 Answers7

41

The & operator performs logical "and" operation for bool operands and is not short circuited.

It's not a sequence point. You cannot rely on the order of evaluation of the operands. However, it's guaranteed that both operands are evaluated.

I do not recommend doing this. Using temporary variables is a better solution. Don't sacrifice readability for "clever code".

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 1
    I'm fairly certain this is the documented standard way to do a non-short circuit boolean operation -- just use the bitwise operator. This also goes for OR (a single | symbol). – Matt G. Nov 18 '09 at 19:56
  • 34
    You'd better put a huge comment around any code that does that - any C developer with more than a year of experience would see `expr1 & expr2` and "fix" it. Using temporary variables is a much better solution. – Graeme Perrow Nov 18 '09 at 19:56
  • 3
    Of course, being pedantic here, the OP asked for a non short circuiting *logical* AND, not a bitwise AND. – Ed S. Nov 18 '09 at 19:59
  • I don't like it on general principles, since it might encourage its use on things that aren't `bool`, and the evaluation of the operands is in undetermined order, which may cause problems if (as in the example) both operands are logging to the same stream. Still, if order of evaluation isn't a problem, it would work here. – David Thornley Nov 18 '09 at 20:00
  • @Ed: For operands of `bool` type, it does "logical" AND. – Mehrdad Afshari Nov 18 '09 at 20:01
  • 9
    @Matt G: That works for booleans, but not in general. `1 && 2` yields `true`, while `1 & 2` yields `0`. – David Thornley Nov 18 '09 at 20:02
  • 1
    Thanks for the response. I'm going to use the temp variables for the actual code as I don't like relying on the "Double-meaning" of "&". It was more of a "this seems to be more lines than it has to be... maybe there is a concise & understandable language feature I don't know" question and Google failed me. – Luciano Nov 18 '09 at 20:04
  • For `bool`, bitwise and boolean is really the same thing, as by definition C++ `bool` is an integral type with only two value values `false==0` and `true=-1`. – Pavel Minaev Nov 18 '09 at 20:34
  • Sory for the typo in the previous comment - of course it's `true==1`. – Pavel Minaev Nov 18 '09 at 20:34
  • @Pavel: Indeed; that's how it works. The point is, you can assign arbitrary integers to bool type (say, `(bool)2 & (bool)1`) and from a higher level of abstraction, it's "logical" and performed on the operands. – Mehrdad Afshari Nov 18 '09 at 21:08
23

and yes, I realize that I could use temporary variables to store the returns of the two functions and then do the "short-circuit" logic on the temporary variables, but I was wondering if there was an "elegant" language solution to keep the one-line return in Func3 while still getting the logging messages from both functions.

That would be the "elegant" solution :). Relying on the side effects of the evaluation order would be far from elegant, error prone, and hard to understand for the next developer who wanders into your project. Relying on the side effects of course contrasts with something like the following snippet, which is a completely logical and valid use case for relying on evaluation order alone:

if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }
Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 4
    I would also recommend putting comments that "these two functions must be executed" or something because otherwise one of those optimistic programmers will come and say "oh these temp variables aren't needed *inline"... either way(& or temp vars) will require comments to clarify their usage – Earlz Nov 18 '09 at 20:00
  • 1
    Of course, relying on side effects may very well be another sign that something is wrong here. – Ed S. Nov 18 '09 at 20:02
  • 1
    Re "Relying on the evaluation order of the AND operator would be far from elegant, error prone, and hard to understand for the next developer who wanders into your project.": There are a lot of cases that I would suggest relying on && evaluation order rather than nesting `if` statements unnecessarily. The canonical example is `if (pSomething != NULL && pSomething->someField) ...` – Mehrdad Afshari Nov 18 '09 at 20:06
  • @Mehrdad: Yes, I do the same, but this situation is not really the same. You are saying "if this is not true do not evaluate the second part", the OP is saying "I want all of these to evaluate because the next function call depends on some side effect, even though the AND does not need to evaluate expressions n+1...2". Perhaps I could word it differently to address this specific use. – Ed S. Nov 18 '09 at 20:26
  • Perhaps even that last comment was poorly worded :). I was just trying to express the fact that your example is a very clean and clear use of the && operator. "Only do this if this is true". That makes sense. The example in the post does not have those semantics. – Ed S. Nov 18 '09 at 20:53
  • @Ed: The side effects are from the logging actions, so I'd assume that they mean whether the logging worked. This seems reasonable to me. – David Thornley Nov 18 '09 at 22:51
  • I don't think it is reasonable to to use & instead of && so that your methods do logging when you could simply store the result in a variable. Anyhow, I don't even get why you would want to call a function that does not need to be called just so it logs some information. – Ed S. Nov 19 '09 at 01:17
14

Yes there are built in operators for doing this. + does a non short circuiting OR and * does an AND.

#include <iostream>
using namespace std;

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

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

Output:

true

false

Motti
  • 110,860
  • 49
  • 189
  • 262
  • 3
    I don't know if I would do that in production code without a big comment, but it is cool nonetheless. – deft_code Nov 18 '09 at 21:43
  • 4
    Very cool! This is why I asked the question: not necessarily to use it in production code, but to learn something. – Luciano Nov 18 '09 at 22:27
  • 1
    it's not "cool", it's "Boole". Boole's algebra... *sigh* the ideological homomorphism between +/* operations and AND/OR was already well known for, like, 100 years? –  Jan 20 '14 at 11:54
  • 1
    @vaxquis maybe, but many languages treat booleans and integers the same, just requiring that statements of the form `if (x) ...` are expanded to `if (x != 0) ...`. For example, in Python 2.x, `print(True + True)` outputs "2". – Ponkadoodle Jan 22 '15 at 03:19
  • 1 || -1 evaluates as true, 1 + -1 evaluates as false, or am I missing something? How about !!a & !!b or, for an or, !!a | !!b ? – Jacques de Hooge Feb 03 '20 at 14:38
  • @JacquesdeHooge `-1` is not a valid `bool` value. – Motti Feb 03 '20 at 14:51
4

You can trivially write your own.

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

And if you want to be very fancy, you could even inline it!!!

Okay, Okay, if you really really don't want the terrible overhead of calling a function.

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

But I don't consider that elegant. It its conceivable that an overly smart compiler could short circuit this...

Sanjaya R
  • 6,246
  • 2
  • 17
  • 19
  • Doesn't your LongCircuitAnd function just reduce down to the regular short-circuit AND (since you return `bool1 && bool2`)? – ThisSuitIsBlackNot Nov 18 '09 at 21:00
  • I took a second look at this...`LongCircuitAnd` works because the arguments you pass it are function calls. These functions (both of them) are executed before you enter the body of `LongCircuitAnd`. However, this approach is misleading, because you still use the short-circuit operator; since you've already seen the side-effects of the two functions, you don't notice the short-circuiting. – ThisSuitIsBlackNot Nov 18 '09 at 21:29
  • 2
    @ThisSuitIsBlackNot - the return expression is short circuited, but both expressions must be evaluated fully to pass to the function as parameters, so long before the `return` statement is reached both 'sub-expressions' have been fully evaluated. – Michael Burr Nov 18 '09 at 21:33
  • @Sanjaya - the compiler couldn't short circuit your multiplication alternative unless the compiler could prove that what it wanted to short circuit had no side effects. In that case it wouldn't matter if the short circuiting took place. – Michael Burr Nov 18 '09 at 21:37
  • I also think that in the spirit of VB.NET's (newish) short circuiting operators (`AndAlso` and `OrElse`) these functions should be named something like `AndEvenIf()` and `OrInAddition()` (jk). – Michael Burr Nov 18 '09 at 22:04
  • 3
    And, in this solution, the order of calling Func1 and Func2 is undetermined. Since the example shows them both logging to the same stream, that might be a problem. – David Thornley Nov 18 '09 at 22:53
3

If you want to use the temporary variables, but keep the return to a single statement, you could use the comma operator:

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

The comma operator forces a sequence point, so each one evaluates its left operand, discards the result, then evaluates its right operand.

Another possibility, but one I'd tend to recommend against, would be for the two functions to return a type that overloads the '&&' operator. Since an overloaded operator invokes a function, it always evaluates both operands, even in cases (like &&) where the built-in operator does not -- usually that's something of a problem, but in this case it's exactly what you want:

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

While this works, it seems to me like it's just a bit too "clever" -- something that wouldn't be at all obvious to most readers. A different name for mybool might help, but offhand I can't think of one that reflects the intent very well without becoming so verbose it would be a net loss.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

Yes. The overloaded versions of operator&& and operator|| do not short-circuit — they evaluate both operands even if the left-hand operand "determines" the outcome... (Source)

That being said, don't overload operator&& or operator||. Be nice to your maintenance programmers who will look at && or || and assume that they do short circuit.

Bill
  • 14,257
  • 4
  • 43
  • 55
  • This is why I think it's a design bug allowing overloading of the `&&` and `||` operators. – Motti Nov 19 '09 at 06:37
  • Nope, it's essential for lambda-like functionality, and there the eventual evaluation (lby definition later) is short-circuited. Unforeseen, but quite useful. – MSalters Nov 20 '09 at 10:01
2

A near-universal but often undocumented non-Standard operator was introduced for exactly this purpose, pioneered by GCC alongside x ?: y (x if non-zero else y), and the now sadly removed >? and <? min/max operators and their compound assignment forms (see http://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html). Sadly, with & and && already in use, they seem to have been scraping the bottom of the barrel to find an appropriate character sequence, but that's just my opinion - would welcome any historical explanations for why this might have been chosen.

So, while it's not currently as well known as many other operators, the >! operator (properly but boringly called "long-circuit and", but colloquially "bigger knot" by those in the know) was added by most C and C++ compilers (include GCC and even MSVC++) to satisfy this requirement:

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

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

Do take it for a spin ;-).

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • 2
    As a (now deleted) answer points out, this isn't actually a new operator (just as `-->` isn't) but simply a strangely formatted `a > !b` which works the same as `a && b` except not short circuited, _as long as_ neither `a` or `b` are negative. – Cubic Oct 24 '18 at 16:01