Consider following piece of code:
static constexpr size_t Num {2};
struct S {
std::array<size_t, Num> get () { return {1, 2}; }
};
struct S1 : S {};
struct S2 : S {};
struct M {
template <typename T>
typename std::enable_if<std::is_same<T, S1>::value, S1>::type get () const {
return S1 {};
}
template <typename T>
typename std::enable_if<std::is_same<T, S2>::value, S2>::type get () const {
return S2 {};
}
};
I want to have a function which merges two or more std::array
s making one std::array
.
So far I ended with something like this:
template <typename Mode, typename... Rs, size_t... Ns>
std::array<size_t, sizeof... (Rs)*Num> get_array (const Mode& mode, Sequence::Sequence<Ns...>) {
return {std::get<Ns> (mode.template get<Rs...> ().get ())...};
}
I want to have that the following code
M m;
auto x = get_array<M, S1, S2> (m, Sequence::Make<2> {});
produces std::array<size_t, 4>
filled with {1, 2, 1, 2}
.
Where Sequence::Sequence
and Sequence::Make
are described here.
I know that placing ...
of Rs
is incorrect in this context (If sizeof... (Rs)
is 1 then it is fine, std::array<size_t, 2>
with {1, 2}
is returned) but I have no idea where to put it to make expansion which looks like this:
std::get<0> (mode.template get<Rs[0]> ().get ()),
std::get<1> (mode.template get<Rs[0]> ().get ()),
std::get<0> (mode.template get<Rs[1]> ().get ()),
std::get<1> (mode.template get<Rs[1]> ().get ());
Of course Rs[0]
I mean first type from parameter pack.
Is it even possible?
Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.
Assuming that we're using Xeo's index sequence implementation, we can do something like this:
First create a function for concatenating two arrays. It receives the arrays, plus an index sequence for each one (detail::seq
is the index_sequence
type)
template<class T, size_t N, size_t M, size_t... I, size_t... J>
std::array<T, N + M> concat(const std::array<T, N>& arr1, const std::array<T, M>& arr2, detail::seq<I...>, detail::seq<J...>)
{
return {arr1[I]..., arr2[J]...};
}
Next, call this function from your get_array
function, except we're going to double the seq
that we received from the call in main
:
template<class MODE, class... T, size_t... I>
auto get_array(MODE m, detail::seq<I...>) ->decltype(concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{})){
return concat(m.template get<T>().get()..., detail::seq<I...>{}, detail::seq<I...>{});
}
The call in main
looks just like it did in your code:
M m;
auto x = get_array<M, S1, S2>(m, detail::gen_seq<2>{});
Where detail::gen_seq
is the implementation of make_index_sequence
that Xeo had.
Note that I replaced unsigned
with size_t
in Xeo's index sequence impl.
In C++14 we don't need to implement seq
or gen_seq
, and we also wouldn't need a trailing -> decltype()
after our function.
In C++17 it would be even easier to generalize our concatenation for an arbitrary number of arrays, using fold expressions.
Yes, this can be done, with the standard index_sequence
tricks:
template <class T, std::size_t N1, std::size_t N2, std::size_t ... Is, std::size_t ... Js>
std::array<T, N1 + N2> merge_impl(const std::array<T, N1>& a1,
const std::array<T, N2>& a2,
std::index_sequence<Is...>,
std::index_sequence<Js...>) {
return {a1[Is]..., a2[Js]...};
}
template <class T, std::size_t N1, std::size_t N2>
std::array<T, N1 + N2> merge(const std::array<T, N1>& a1, const std::array<T, N2>& a2) {
return merge_impl(a1, a2,
std::make_index_sequence<N1>{},
std::make_index_sequence<N2>{});
}
index_sequence
is only in the 14 standard, but can be easily implemented in 11; there are many resources (including on SO) that describe how to do so (edit: it's basically equivalent to your Sequence
stuff, may as well get used to the standard names for them). Live example: http://coliru.stacked-crooked.com/a/54dce4a695357359.
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