Reputation: 267
I want to prepare list of pairs of values from structure using variadic templates.
#include <vector>
struct foo
{
foo(int a, int b)
: a(a), b(b) {}
int a;
int b;
};
struct Msg
{
std::vector<int> valueArray;
};
template<typename... Args>
Msg func(Args... args)
{
Msg msg;
msg.valueArray = { sizeof...(args), (args.a)..., (args.b)... };
return msg;
}
int main() {
Msg msg = func(foo{1,2}, foo{3,4}, foo{5,6});
}
Msg which func will return will have valueArray = [3, 1, 3, 5, 2, 4, 6]
.
Is there any simple way to expand variadic paremeters in a way, where valueArray will look like valueArray = [3, 1, 2, 3, 4, 5, 6]
?
Upvotes: 6
Views: 137
Reputation: 56863
The following is not as generic as I'd like to, but maybe it is sufficient for you:
template<typename Arr, std::size_t... Is>
Msg func2( const Arr& arr, std::index_sequence<Is...> )
{
Msg msg;
msg.valueArray = {
sizeof...(Is) / 2,
( ( Is % 2 == 0 ) ? std::get< Is / 2 >( arr ).a
: std::get< Is / 2 >( arr ).b )... };
return msg;
}
template<typename... Args>
Msg func(Args... args)
{
return func2( std::forward_as_tuple( args... ),
std::make_index_sequence< 2*sizeof...(Args) >() );
}
Upvotes: 4
Reputation: 60999
Using C++14 features, a general solution can be obtained:
struct Msg {
std::vector<int> values;
};
template <std::size_t... indices, typename Tuple, typename OutputIt>
void copy(std::index_sequence<indices...>, Tuple&& t, OutputIt out) {
(void)std::initializer_list<int> {
(*out++ = std::get<indices>(std::forward<Tuple>(t)), 0)...
};
}
template <typename Tuple, typename OutputIt>
void copy(Tuple&& t, OutputIt out) {
copy(std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{},
std::forward<Tuple>(t), out);
}
template <typename... Args>
Msg func(Args... args) {
auto cat = std::tuple_cat(args...);
Msg m{{sizeof...(args)}};
copy(cat, std::back_inserter(m.values));
return m;
}
// For demonstration:
template <typename... T>
auto foo(T&&... t) {return std::make_tuple(std::forward<T>(t)...);}
The usage is more flexible than before:
Msg msg = func(foo(1,2,3), foo(4), foo(5,6,7));
Demo.
You can define foo
to be a (fixed sized) tuple as well, e.g. using foo = std::tuple<int, int>;
, then your above example compiles without the auxiliary function (after adjusting the braces, of course).
Upvotes: 3