In a nested requirement, why use `requires bool_constant<X>::value;` instead of `requires X;`?

Viewed 162

I was reading this cppreference page, and found following code in it:

template <class G>
concept uniform_random_bit_generator =
  // ...
  requires {
    // ...
    requires std::bool_constant<(G::min() < G::max())>::value;
  };

I'm curious why std::bool_constant is used here. Isn't it possible to use requires G::min() < G::max(); directly, like so:

template <class G>
concept uniform_random_bit_generator =
  // ...
  requires {
    // ...
    requires G::min() < G::max();
  };
1 Answers

Because requires G::min() < G::max(); is a hard error if G::min() < G::max() doesn't form a constant expression, but requires std::bool_constant<(G::min() < G::max())>::value would just be false.

Take for example this type and these concepts:

struct foo {
    static int min();
    static int max();
};

template<typename T>
concept min_max_1 = requires {
    requires T::min() < T::max();
};

template<typename T>
concept min_max_2 = requires {
    requires std::bool_constant<(T::min() < T::max())>::value;
};

// Which are entirely equivalent to
template<typename T>
concept min_max_1 = T::min() < T::max();

template<typename T>
concept min_max_2 = std::bool_constant<(T::min() < T::max())>::value;

static_assert(!min_max_2<foo>); succeeds as expected, because it forms an invalid expression so it is false.

static_assert(!min_max_1<foo>); creates a compile time error, because T::min() < T::max() is a valid expression, it's just not a bool constant expression, which is what is expected.

Related