How do you static_assert the values in a parameter pack of a variadic template?

Venemo picture Venemo · Apr 29, 2016 · Viewed 7k times · Source

I'm creating a variadic template.
Let's say I have something like this:

template<typename T, T ... Numbers>
class Sequence final {

    // Unpack parameter pack into a constexpr array
    constexpr static T count = sizeof...(Numbers);        
    constexpr static T numbers[count] = { Numbers... };

    // ...
}

Instances of this class can be instantiated like:

Sequence<uint32_t, 1, 2, 3, 42, 25> seq;

I'd like to make sure at compile time using a static_assert that the numbers parameter pack only contains specific numbers. For the sake of this example, let's say I only want to allow 0 or 1.

So I'd like to do something like:

for (size_t i = 0; i < count; i++) {
    static_assert(numbers[i] == 1 || numbers[i] == 0, "Only ones and zeroes are allowed.");
}

But obviously, static_assert doesn't work with a for loop. I'm pretty sure there must be some sort of syntax for this but I haven't been able to figure it out.

I'd prefer to use something that compiles with a C++11 compiler (or perhaps a C++14 compiler, if it isn't doable in C++11).

Answer

T.C. picture T.C. · Apr 29, 2016

I'll throw in @Columbo's bool_pack trick.

template<bool...> struct bool_pack;
template<bool... bs> 
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;

static_assert(all_true<(Numbers == 0 || Numbers == 1)...>::value, "");

Extract the expression into a constexpr function if it gets complex.