Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I map a C++ parameter pack into a sequence of std::pair objects?

Tags:

c++

c++11

I have a variadic template function foo():

template <typename... Args>
void foo(Args &&... args);

This function is intended to be invoked with all arguments of size_t. I can enforce that using some metaprogramming. I need to take the resulting list of arguments two at a time and put them into a container of std::pair<size_t, size_t>. Conceptually, something like:

std::vector<std::pair<size_t, size_t> > = { 
    std::make_pair(args[0], args[1]), 
    std::make_pair(args[2], args[3]), ...
};

Is there a straightforward way to do this? I know that by pack expansion, I could put the arguments into a flat container, but is there a way to group them two by two into std::pair objects at the same time?

like image 375
Jason R Avatar asked Dec 10 '22 13:12

Jason R


2 Answers

Indexing into packs isn't really doable (yet?), but indexing into tuples is. Just stick everything into a tuple first, and then pull everything back out as you go. Since everything's a size_t, we can just copy:

template <size_t... Is, class Tuple>
std::vector<std::pair<size_t, size_t>> 
foo_impl(std::index_sequence<Is...>, Tuple tuple) {
    return std::vector<std::pair<size_t, size_t> >{ 
        std::make_pair(std::get<2*Is>(tuple), std::get<2*Is+1>(tuple))...
    };
}

template <typename... Args>
void foo(Args... args)
{
    auto vs = foo_impl(std::make_index_sequence<sizeof...(Args)/2>{},
        std::make_tuple(args...));

    // ...
}
like image 160
Barry Avatar answered Dec 13 '22 02:12

Barry


Suppose you are allowed to refactor your logic into an internal helper function:

template <typename ...Args>
void foo(Args &&... args)
{
    foo_impl(std::make_index_sequence<sizeof...(Args) / 2>(),
             std::forward<Args>(args)...);
}

Now we can operate on the argument pack index by index:

template <std::size_t ...I, typename ...Args>
void foo_impl(std::index_sequence<I...>, Args &&... args)
{
    std::vector<std::pair<std::size_t, std::size_t>> v =
        { GetPair(std::integral_constant<std::size_t, I>(), args...)... };
}

It remains to implement the pair extractor:

template <typename A, typename B, typename ...Tail>
std::pair<std::size_t, std::size_t> GetPair(std::integral_constant<std::size_t, 0>,
                                            A a, B b, Tail ... tail)
{
    return { a, b };
}

template <std::size_t I, typename A, typename B, typename ...Tail>
std::pair<std::size_t, std::size_t> GetPair(std::integral_constant<std::size_t, I>,
                                            A a, B b, Tail ... tail)
{
    return GetPair<I - 1>(tail...);
}
like image 28
Kerrek SB Avatar answered Dec 13 '22 02:12

Kerrek SB