I have function like this:
template <typename ... Types>
void foo(const Types & ... values)
{
// expected that 'values' is sequence like
// '1, customvalue1, 2, customvalue2, 3,...'
}
And second function:
template <typename ... Types>
void bar(const Types & ... values)
{
// where 'values' are any variables
// some magic here
foo((int_seq<sizeof...(Types)>, values)...);
}
I'd like to pass any sequence of variables to bar, so that this sequence convert to sequence like '1, value1, 2, value2, 3, value3'. So each value follows its number in base sequence. But I cannot create this 'magic code' to transform sequence on compile phase between this two state.
Not really elegant but, using tuples, std::tie
, etc...
The following example should work with C++11
--- EDIT ---
Modified and unified (C++11 without C++14 elements) my first example.
There is no need of std::index_sequence
(a trivial struct indSeq
can be used instead) or std::make_index_sequence
(the index sequence can be contructed step by step using sizeof...(I)
); no need of qux()
anymore.
#include <tuple>
#include <iostream>
void foo ()
{ }
template <typename T0, typename ... Types>
void foo (const T0 & v0, const Types & ... values)
{
std::cout << "-- " << v0 << std::endl;
foo(values...);
}
template <std::size_t ...>
struct indSeq
{ };
template <std::size_t ... Is, typename ... Ts1>
void baz (std::size_t, const indSeq<Is...> &, const std::tuple<Ts1...> & t)
{ foo(std::get<Is>(t)...); }
template <std::size_t ... Is, typename ... Ts1, typename T0, typename ... Ts2>
void baz (std::size_t n, const indSeq<Is...> &, const std::tuple<Ts1...> & t,
const T0 & v0, const Ts2 & ... vs)
{ baz(n+1U, indSeq<Is..., sizeof...(Is), sizeof...(Is)+1U>(),
std::tuple_cat(t, std::tie(n), std::tie(v0)), vs...); }
template <typename ... Types>
void bar (const Types & ... values)
{ baz (1U, indSeq<>(), std::tuple<>(), values...); }
int main()
{
bar(11, 22L, "33", 44.44);
return 0;
}
p.s.: sorry for my bad English.
Here's a C++14 solution, but all the necessary library parts can be written in C++11 as well.
#include <iostream>
#include <tuple>
#include <utility>
template <typename ... Types>
void foo(const Types & ... values)
{
using swallow = bool[];
(void)swallow{ (std::cout << values << std::endl,false)... };
}
template <std::size_t N, bool = (N%2==0)>
struct pick {
template<typename... Types>
static std::size_t get(const std::tuple<Types...>&) { return N/2; }
};
template <std::size_t N>
struct pick<N,false> {
template<typename... Types>
static auto get(const std::tuple<Types...>& t) { return std::get<N/2>(t); }
};
template <std::size_t... Indices, typename ... Types>
void bar2(const std::index_sequence<Indices...>, const Types & ... values)
{
auto x = std::tie(values...);
foo(pick<Indices>::get(x)...);
}
template <typename ... Types>
void bar(const Types & ... values)
{
bar2(std::index_sequence_for<Types...,Types...>(), values...);
}
int main()
{
bar( "Hallo", 42, 1.23 );
}
Live example
It is currently zero-based, but a +1
in the right place will fix that easily. Also, it creates an intermediate std::tuple
with references to the values, if performance is an issue better options might exist but since you weren't using std::forward
I figured that a small performance impact might be acceptable for you.
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