Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create custom integer sequence in C++

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.

like image 451
wannabe programmer Avatar asked Aug 03 '16 17:08

wannabe programmer


2 Answers

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.

like image 175
max66 Avatar answered Oct 18 '22 01:10

max66


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.

like image 20
Daniel Frey Avatar answered Oct 18 '22 02:10

Daniel Frey