按给定类型拆分参数包

Split a parameter pack at a given type

本文关键字:参数 拆分 类型      更新时间:2023-10-16

如何根据给定的分隔符类型拆分参数包?例如:

struct separator {
  // ...
};
struct foo1 {
  foo1(int a, int b) {...}
};
struct foo2 {
  foo2(double a, double b, double c) {...}
};
template <typename... ArgsT>
void func(ArgsT&&... args) {
   // args have two separators
   auto f1 = foo1(/*How can I get the argument list to construct foo1?*/);
   auto f2 = foo2(/*same as above*/);
   auto f3 = ....
}
separator s1, s2;
func(s1, 1, 2, s2, 4.5, 6.7, 7.8);

在上面的例子中,给定的args保证至少有一个类型为separator的参数。每个分隔符后面跟着一个参数列表来构造一个结构体(例如,foo1foo2等等)。基于c++ 14或c++ 1z的解决方案。

好的,我想我知道了。

#include <functional>
#include <iostream>
template<typename T>
T recrusiveSearchHelper(int which,int current, T last)
{
    return last;
};
template<typename T, typename... Args>
T recrusiveSearchHelper(int which,int current,T first,Args... args)
{
    if (which == current)
    {
        return first;
    }
    recrusiveSearchHelper(which,current + 1,args...);
}
template <typename T,typename... Args>
T recrusiveSearch(int which, T first, Args... args)
{
    return recrusiveSearchHelper(which,0,first,args...);
}

struct Seperator 
{
};
void foo2(double a,double b,double d)
{
    std::cout << "Foo two: " << a << " : " << b << " : " << d << std::endl;
};
void foo1(int a,int b)
{
    std::cout << "Foo One: " << a << " : "<< b << std::endl;
};
void zipper(int& index,std::function<void(int)>fn, Seperator s)
{
    index++;
    fn(index);  
}
template <typename T>
void zipper(int& index, std::function<void(int)>fn, T data)
{
    index++;
};
template <typename T,typename... Args>
void zipper(int& index, std::function<void(int)> fn,T first, Args... args)
{
    index++;
    zipper(index,fn,args...);
};
template <typename... Args>
void zipper(int& index, std::function<void(int)> fn,Seperator first, Args... args)
{
    index++;
    fn(index);
    zipper(index,fn,args...);
};
template <typename T,typename... Args>
void useWithSeperator(T first,Args... args)
{
    int index = 0;
    int current = 0;
    std::function <void(int)> fn = [&current,first,args...](int where)
    {
        if (where - current == 3)
        {
            foo1(recrusiveSearch(where-3,first,args...),recrusiveSearch(where-2,first,args...));
        }else if (where - current == 4)
        {
            foo2(recrusiveSearch(where-4,first,args...),recrusiveSearch(where-3,first,args...),recrusiveSearch(where-2,first,args...));
        }
        current = where;
    };
    zipper(index,fn,first);
    zipper(index,fn,args...);
};
int main(int argc, char **argv)
{
    useWithSeperator(1,2,3,Seperator(),4,5,Seperator(),1,1,2,3,4,Seperator(),1,2,5,Seperator());
}

这有点混乱,但是它的作用是通过一个辅助变量模板来缩小每次迭代的搜索范围,直到Element在其递归循环中第一次成为我们想要的位置的元素。剩下的就很简单了,我们需要检索数据并跟踪我们的周期。

首先,不这样做,取元组并从所述元组构造对象。

func(std::make_tuple(1, 2), std::make_tuple(4.5, 6.7, 7.8));

不管怎么做,我们最后都会到这里来的。

如果失败,编写一个函数,该函数接受std::tuple<Ts...>并将其拆分为分隔符上的std::tuple< std::tuple<???>... > tuple_of_tuples拆分,然后执行std::apply( good_func, tuple_of_tuples )

namespace details {
  struct adl_helper {};
  template<class Sep, class...Cs, class...Zs>
  auto tuple_splitter( adl_helper, std::tuple<> in, std::tuple<Cs...> working, std::tuple<Zs...> out ) {
    (void)in;
    return std::tuple_cat( std::move(out), std::make_tuple(working) );
  }
  template<class Sep, class T0, class...Ts, class...Cs, class...Zs,
    std::enable_if_t<!std::is_same<T0, Sep>{}, int> =0
  >
  auto tuple_splitter( adl_helper, std::tuple<T0, Ts...> in, std::tuple<Cs...> working, std::tuple<Zs...> out ) {
    auto in_indexer = indexer<sizeof...(Ts)>();
    return tuple_splitter<Sep>(
      adl_helper{},
      in_indexer( [&](auto...i){ return std::forward_as_tuple( std::get<i+1>(std::move(in))...); } ),
      std::tuple_cat( std::move(working), std::make_tuple( std::get<0>(in) ) ), 
      std::move(out)
    );
  }
  template<class Sep, class...Ts, class...Cs, class...Zs>
  auto tuple_splitter( adl_helper, std::tuple<Sep, Ts...> in, std::tuple<Cs...> working, std::tuple<Zs...> out ) {
    auto in_indexer = indexer<sizeof...(Ts)>();
    return tuple_splitter<Sep>(
      adl_helper{},
      in_indexer( [&](auto...i){ return std::forward_as_tuple( std::get<i+1>(std::move(in))...); } ),
      std::make_tuple(),
      std::tuple_cat( std::move(out), std::make_tuple(working) )
    );
  }
}
template<class Sep, class...Ts>
auto tuple_splitter( std::tuple<Ts...> tuple ) {
  return details::tuple_splitter<Sep>( details::adl_helper{}, std::move(tuple), std::make_tuple(), std::make_tuple() );
}

现在tuple_splitter<Bob>( some_tuple )将把some_tuple拆分为元组的元组,每个子元组的元素由Bob分隔。

生活例子。

我使用我的indexer实用程序弹出元组的第一个元素。它允许您在不离开当前函数体的情况下获得编译时的整数包。

template<class=void,std::size_t...Is>
auto indexer( std::index_sequence<Is...> ) {
  return [](auto&&f)->decltype(auto) {
    return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
  };
}
// takes a number N
// returns a function object that, when passed a function object f
// passes it compile-time values from 0 to N-1 inclusive.
template<std::size_t N>
auto indexer() {
  return indexer( std::make_index_sequence<N>{} );
}