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_>;
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With