Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a variadic template from a constexpr array

Tags:

c++

c++11

c++14

Let's say we have the following type

template <bool... Values>
struct foo{};

I want to create a variadic template from a constexpr array bool tab[N]. In other words, I want to do something like:

constexpr bool tab[3] = {true,false,true};
using ty1 = foo<tab[0], tab[1], tab[2]>;

But I want to do it programmatically. For now, I've tried the following:

template <std::size_t N, std::size_t... I>
auto
mk_foo_ty(const bool (&tab)[N], std::index_sequence<I...>)
{
  // error: template argument for template type parameter must be a type
  return foo<tab[I]...>{};
}

// error (see mk_foo_ty)
using ty2 = decltype(mk_ty(tab, std::make_index_sequence<3>{}));

// error: expected '(' for function-style cast or type construction
using ty3 = foo<(tab[std::make_index_sequence<3>])...>;

I'm not even sure if it's possible. Maybe resorting to something like Boost.Preprocessor, but I don't like the idea. So, does anyone have an idea? Thanks!

EDIT

I have on one side a framework of constexpr square matrices of booleans which can be created at compile-time using xor, negation, etc.

On the other side, I have a framework of templates which statically creates operations using informations encoded in variadic templates using boolean as parameters.

My goal is to bridge the gap between these two frameworks. Thus, I can't go with hardcoded solutions.

EDIT 2

I've found this question with the same problem and a nice answer, which is very close to the T.C.'s one (using a pointer). The extern linkage is also very important.

However, I realize I forgot a key element. My bool array is contained in a matrix structure to be able to overload operators ^, |, etc.:

template <std::size_t N>
struct matrix
{
  const bool data_[N*N];

  template<typename... Values>
  constexpr matrix(Values... values) noexcept
    : data_{static_cast<bool>(values)...}
  {}

  constexpr bool operator [](std::size_t index) const noexcept
  {
    return data_[index];
  }
}

Thus, if we apply T.C's solution:

template<std::size_t N, const bool (&Tab)[N], class>
struct ty1_helper;

template<std::size_t N, const bool (&Tab)[N], std::size_t... Is>
struct ty1_helper<N, Tab, std::index_sequence<Is...>>
{
  using type = foo<Tab[Is]...>;
};

template<std::size_t N, const bool (&Tab)[N]>
using ty1 = typename ty1_helper<N, Tab, std::make_index_sequence<N>>::type;

Compilers complain about passing a non-type parameter :

// error: non-type template argument does not refer to any declaration
//        using t = make_output_template<m.data_, std::make_index_sequence<3>>;
//                                       ^~~~~~~
using t = ty1<3, m.data_>;
like image 967
Alexandre Hamez Avatar asked Oct 31 '22 12:10

Alexandre Hamez


1 Answers

The way I did it in the comments above, using a global constexpr variable with external linkage (necessary due to GCC's nonconforming external linkage requirement, see bug 52036), would probably blow up spectacularly at link time if you put it in a header and include the header in different translation units. A solution that's good for one translation unit only isn't much of a solution. One workaround is to store the matrix as a static data member of a class.

struct matrix_holder {
    static constexpr matrix<2> mat = {true, false, true, false};
};

template<std::size_t N, const matrix<N> &Mat, class> 
struct ty1_helper;

template<std::size_t N, const matrix<N> &Mat, std::size_t... Is>
struct ty1_helper<N, Mat, std::index_sequence<Is...>> { 
    using type = foo<Mat[Is]...>; 
};

template<std::size_t N, const matrix<N> &Mat>
using ty1 = typename ty1_helper<N, Mat, std::make_index_sequence<N*N>>::type;

static_assert(std::is_same<ty1<2, matrix_holder::mat>,
                           foo<true, false, true, false>>::value, "Oops");

Demo. Also, since using matrix_holder::mat in ty1<2, matrix_holder::mat> counts as an odr-use, to be fully conforming you should supply a definition:

constexpr matrix<2> matrix_holder::mat;
like image 145
T.C. Avatar answered Nov 04 '22 09:11

T.C.