The Boolean concept specifies the requirements on a type that is usable in Boolean contexts.
template <class B>
concept bool Boolean =
Movable<decay_t<B>> && // (see [concepts.lib.object.movable])
requires(const remove_reference_t<B>& b1,
const remove_reference_t<B>& b2, const bool a) {
{ b1 } -> ConvertibleTo<bool>&&;
{ !b1 } -> ConvertibleTo<bool>&&;
{ b1 && a } -> Same<bool>&&;
{ b1 || a } -> Same<bool>&&;
{ b1 && b2 } -> Same<bool>&&;
{ a && b2 } -> Same<bool>&&;
{ b1 || b2 } -> Same<bool>&&;
{ a || b2 } -> Same<bool>&&;
{ b1 == b2 } -> ConvertibleTo<bool>&&;
{ b1 == a } -> ConvertibleTo<bool>&&;
{ a == b2 } -> ConvertibleTo<bool>&&;
{ b1 != b2 } -> ConvertibleTo<bool>&&;
{ b1 != a } -> ConvertibleTo<bool>&&;
{ a != b2 } -> ConvertibleTo<bool>&&;
};
Given const lvalues b1 and b2 of type remove_reference_t<B>, then Boolean<B> is satisfied only if
bool(b1) == !bool(!b1).
(b1 && b2), (b1 && bool(b2)), and (bool(b1) && b2) are all equal to (bool(b1) && bool(b2)), and have the same short-circuit evaluation.
(b1 || b2), (b1 || bool(b2)), and (bool(b1) || b2) are all equal to (bool(b1) || bool(b2)), and have the same short-circuit evaluation.
bool(b1 == b2), bool(b1 == bool(b2)), and bool(bool(b1) == b2) are all equal to (bool(b1) == bool(b2)).
bool(b1 != b2), bool(b1 != bool(b2)), and bool(bool(b1) != b2) are all equal to (bool(b1) != bool(b2)).
[ Example: The types bool, std::true_type, and std::bitset<N>::reference are Boolean types. Pointers, smart pointers, and types with explicit conversions to bool are not Boolean types. — end example ]