Creating a variational pattern from a constexpr array

Say we have the following type

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

I want to create a variation template from the constexpr bool tab[N] array. 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 this programmatically. At the moment, I have 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 that this is possible. Perhaps resorting to something like Boost.Preprocessor, but I don't like this idea. So, does anyone have any ideas? Thanks!

EDIT

On the one hand, I have a constexpr structure of square Boolean matrices that can be created at compile time using xor, negation, etc.

On the other hand, I have a template structure that statically creates operations using information encoded in variable templates, using boolean as parameters.

My goal is to bridge the gap between these two structures. Thus, I cannot go with hard-coded solutions.

EDIT 2

I found this question with the same problem and a nice answer that is very close to TC alone (using a pointer). extern communication is also very important.

However, I understand that I forgot a key element. My bool array is contained in a matrix structure to be able to overload the ^, | 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 you apply the TC 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 the transfer of non-pig 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_>; 
+5
source share
1 answer

The way I did this in the comments above using the global constexpr variable with external linkage (necessary due to a mismatch in the GCC external linkage, see error 52036 ) will probably explode spectacularly during the connection if you put it in the header and turn it on heading into different translation units. A solution that is suitable for only one translation unit is not a solution. One way is to save the matrix as a static member of the class data.

 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 In addition, since using matrix_holder::mat in ty1<2, matrix_holder::mat> is considered odr-use, to be fully compatible, you must provide a definition:

 constexpr matrix<2> matrix_holder::mat; 
+2
source

Source: https://habr.com/ru/post/1209650/


All Articles