3

I`am trying to find a simple way of checking if parameters passed as template arguments are all power of 2. I found a bithack on the website and I have this:

constexpr bool isPowerOf2(size_t value){
return !(value == 0) && !(value & (value - 1));
}

This works nice for single value but applying this to multiple arguments looks ugly.

static_assert(isPowerOf2(Arg1), "Argument must be a power of 2");
static_assert(isPowerOf2(Arg2), "Argument must be a power of 2");
static_assert(isPowerOf2(Arg3), "Argument must be a power of 2");

It would be better if I could make it look like arePowersOf2(Arg1, Arg2, Arg3), but im not really advanced in template magic. So my question: Is there an easy way of doing it? I would prefer constexpr C++11 solution.

TomW
  • 43
  • 4

2 Answers2

7

You can write a conjunction trait which checks if all the bools in a parameter pack are true. This example uses @Columbo's bool_pack trick:

template <bool...> struct bool_pack{};
template <bool... bools> 
struct conjunction : std::is_same<bool_pack<true, bools...>,
                                  bool_pack<bools..., true>>
{};

template <size_t... Args>
constexpr bool arePowerOf2() {
    return conjunction<isPowerOf2(Args)...>::value;   
}

Then you would just call it like this:

arePowerOf2<Args...>();
arePowerOf2<Arg1, Arg2, Arg3>();

Live Demo


In C++1z you can use fold expressions for this:

template <size_t... Args>
constexpr bool arePowerOf2() {
    return (... && isPowerOf2(Args));
}

C++1z will also get std::conjunction, which is just slightly different from the version above.

Community
  • 1
  • 1
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
1

A pack of bools is an integer sequence of bools:

template<bool...Bs>using bools = std::integer_sequence<bool, Bs...>;

These help you create a sequence of true, true, true of a specified length:

template<std::size_t...Is>
constexpr bools<(Is,true)...> make_trues_f( std::index_sequence<Is...> ) {
  return {};
}
template<std::size_t N>
using make_trues_t = decltype( all_true_f( std::make_index_sequence<N>{} ) );
template<class...Ts>
using make_trues_for_t = make_trues_t<sizeof...(Ts)>;

which gives you:

static_assert(
  std::is_same<
    bools<isPowerOf2(Args)...>,
    make_trues_for_t<Args...>
  >::value, "Argument must be a power of 2"
);

or

template<class...Args>
constexpr std::is_same<
    bools<isPowerOf2(Args)...>,
    make_trues<sizeof...(Args)>
  >
all_power_of_2() { return {}; }

Me, I like returning types even from constexpr functions when I know the answer at a type-computation level.

As a bonus, the failed comparison is more clearly what is intended, instead of an off-by-one hack. The is_same compares a sequence of <true, true, false, true> to <true, true, true, true>, as compared to the off-by-one hack which compares <true, true, true, false, true> to <true, true, false, true, true>. In the first case, it is really clear from the type what went wrong -- the false -- especially when you spot that the right hand side is always a pack of only true.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524