views:

418

answers:

6

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.

+20  A: 

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 Swangren
Earlz
Agreed [15chars]
Ed Swangren
Of course, relying on side effects may very well be another sign that something is wrong here.
Ed Swangren
Mehrdad Afshari
@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 Swangren
Ed Swangren
@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
Ed Swangren
+12  A: 

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
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.
Graeme Perrow
@jprete, yes there is.
Earlz
Of course, being pedantic here, the OP asked for a non short circuiting *logical* AND, not a bitwise AND.
Ed Swangren
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
@Graeme: Comment added.
Mehrdad Afshari
@Ed: For operands of `bool` type, it does "logical" AND.
Mehrdad Afshari
David Thornley
Luciano
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
Sory for the typo in the previous comment - of course it's `true==1`.
Pavel Minaev
Mehrdad Afshari
+4  A: 

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
ThisSuitIsBlackNot
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
@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
@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
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
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
+2  A: 

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
Motti
Nope, it's essential for lambda-like functionality, and there the eventual evaluation (lby definition later) is short-circuited. Unforeseen, but quite useful.
MSalters
+3  A: 

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
I like this. It keeps the evaluation in order.
David Thornley
+7  A: 

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
I don't know if I would do that in production code without a big comment, but it is cool nonetheless.
caspin
Very cool! This is why I asked the question: not necessarily to use it in production code, but to learn something.
Luciano