如何将C ++参数包映射到std :: pair对象序列?

时间:2017-01-24 19:51:37

标签: c++ c++11

我有一个可变参数模板函数foo()

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

此函数旨在使用size_t的所有参数调用。我可以使用some metaprogramming强制执行此操作。我需要一次获取两个参数的结果列表,并将它们放入std::pair<size_t, size_t>的容器中。从概念上讲,类似于:

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

有直接的方法吗?我知道通过包扩展,我可以将参数放入一个扁平的容器中,但是有没有办法将它们两个一起分组到std::pair个对象中?

4 个答案:

答案 0 :(得分:7)

索引到包中并不是真的可行(但是?),但索引到元组是。首先将所有内容都粘贴到一个元组中,然后随时将所有内容拉回来。由于一切都是size_t,我们可以复制:

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...));

    // ...
}

答案 1 :(得分:2)

假设您被允许将逻辑重构为内部帮助函数:

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

现在我们可以通过索引对参数包索引进行操作:

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...)... };
}

它仍然是实现配对提取器:

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...);
}

答案 2 :(得分:2)

使用range-v3,您可以

template <typename... Args>
void foo(Args&&... args)
{
    std::initializer_list<std::size_t> nbs = {static_cast<std::size_t>(args)...};
    const auto pair_view =
        ranges::view::zip(nbs | ranges::view::stride(2),
                          nbs | ranges::view::drop(1) |  ranges::view::stride(2));

    // And possibly
    std::vector<std::pair<std::size_t, std::size_t>> pairs = pair_view;
    // ...
}

Demo

答案 3 :(得分:1)

某人(咳嗽 @Barry 咳嗽)表示不能将包索引到包中。

这是C ++。不可能意味着我们还没有写出它。

template<std::size_t I> struct index_t:std::integral_constant<std::size_t, I> {
  using std::integral_constant<std::size_t, I>::integral_constant;
  template<std::size_t J>
  constexpr index_t<I+J> operator+( index_t<J> ) const { return {}; }
  template<std::size_t J>
  constexpr index_t<I-J> operator-( index_t<J> ) const { return {}; }
  template<std::size_t J>
  constexpr index_t<I*J> operator*( index_t<J> ) const { return {}; }
  template<std::size_t J>
  constexpr index_t<I/J> operator/( index_t<J> ) const { return {}; }
};
template<std::size_t I>
constexpr index_t<I> index{};

template<std::size_t B>
constexpr index_t<1> exponent( index_t<B>, index_t<0> ) { return {}; }

template<std::size_t B, std::size_t E>
constexpr auto exponent( index_t<B>, index_t<E> ) {
  return index<B> * exponent( index<B>, index<E-1> );
}
template<std::size_t N>
constexpr index_t<0> from_base(index_t<N>) { return {}; }
template<std::size_t N, std::size_t c>
constexpr index_t<c-'0'> from_base(index_t<N>, index_t<c>) { return {}; }
template<std::size_t N, std::size_t c0, std::size_t...cs>
constexpr auto from_base(index_t<N>, index_t<c0>, index_t<cs>...) {
  return 
    from_base(index<N>, index<c0>) * exponent(index<N>, index<sizeof...(cs)>)
    + from_base(index<N>, index<cs>...)
  ;
}

template<char...cs>
constexpr auto operator""_idx(){
  return from_base(index<10>, index<cs>...);
}

auto nth = [](auto index_in){
  return [](auto&&...elems)->decltype(auto){
    using std::get;
    constexpr auto I= index<decltype(index_in){}>;
    return get<I>(std::forward_as_tuple(decltype(elems)(elems)...));
  };
};

现在我们得到:

using pair_vec = std::vector<std::pair<std::size_t, std::size_t>>;
template <typename... Args>
pair_vec foo(Args &&... args) {
  return
    index_over< sizeof...(args)/2 >()
    ([&](auto...Is)->pair_vec{
      return {
        {
          nth( Is*2_idx )( decltype(args)(args)... ),
          nth( Is*2_idx+1_idx )( decltype(args)(args)... )
        }...
      };
    });
}

我们&#34;直接&#34;使用编译时常量索引索引我们的参数包。

live example