5

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_>;
10
  • How far do you want to push this? Is it OK to hardcode tab and its size or do you want something more general? Commented Dec 21, 2014 at 13:36
  • 2
    coliru.stacked-crooked.com/a/1ed4f214047febac Commented Dec 21, 2014 at 13:50
  • Which language are you using? C++11 or C++14? (It looks distinctly like the latter, to me...) Commented Dec 21, 2014 at 13:59
  • Are you looking for the indices trick? Commented Dec 21, 2014 at 14:00
  • @LightnessRacesinOrbit I use C++14 in this example to simplify the creation of indices, but it could be in C++11 using the appropriate replacement. Commented Dec 21, 2014 at 14:37

1 Answer 1

2

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;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.