Decisions in if-statements often have to be based on one or more conditions evaluating to (logically) true or false. There are three *logical* operators in C++ which operate on expressions and yield a boolean result; they are “and” (`&&`

), “or” (`||`

) and “not” (`!`

). Modern C++ allows the keywords `and`

, `or`

and `not`

to be used instead of the more traditional symbolic versions; there is no difference between the two and the keywords may even be implemented as macros.

Both of the binary operators (“or” and “and”) “short-circuit” which means that the value of the first operand determines whether the second is evaluated at all:

```
bool f() {
cout << "f()\n";
return false;
}
bool t() {
cout << "t()\n";
return !false;
}
auto b1 = f() && t(); // result false, t() not even called
auto b2 = t() || f(); // result true, f() not even called
```

Interestingly, the use of the *bitwise* operators (each with a single symbol instead of a double) instead is equally valid here, and bypasses the short-circuit behavior:

```
auto b3 = f() & t(); // result as b1, both f() and t() are called
auto b3 = t() | f(); // result as b2, both f() and t() are called
```

For this to work equivalently, both operands must be explicitly `bool`

, not just implicitly convertible (values such as `0.0`

and `nullptr`

convert to `false`

implicitly). Another way ensuring that both functions are always called would be to assign them to different variables, and apply the logical operators to these variables.

Before we write off *short-circuit evaluation* completely, an example of where it is not just desirable but necessary is testing a pointer against `false`

, and only dereferencing it if non-`nullptr`

:

```
void print_chars(const char *p) {
if (p && *p) {
cout << p << '\n';
}
}
print_chars(nullptr); // no output
print_chars(""); // again, no output - can you work out why?
print_chars("Booleans are awesome!");
// outputs this message followed by a newline
```

The bitwise operators work on any integer type, and also `std::bitset`

. Where both operands have a number of set bits, as opposed to just the least significant bit, bits at equal positions are compared. They have the names `bitand`

(`&`

), `bitor`

(`|`

), `bitxor`

(`^`

) and `compl`

(`~`

). Here are some examples using two four-bit values `a = 0b0110`

and `b = 0b1010`

:

Operation | Modern C++ style | Result |

`~a` | `compl a` | `0b1001` |

`a & b` | `a bitand b` | `0b0100` |

`a | b` | `a bitor b` | `0b1110` |

`a ^ b` | `a bitxor b` | `0b1100` |

Just a quick note on `bitxor`

, it follows that the expression `a ^ a`

is always zero regardless of the value of `a`

. This means that “exclusive-or” operations are always reversible, which is why they are often used in the generation of hash-values and for encryption methods.

In summary, with logical condition tests conversion of both operands to boolean are implied and the second operand is not always evaluated. With bitwise tests the operands can be boolean or integer, and in the case of the latter all bits are significant.