拆分给定类型的参数包

时间:2016-11-15 04:43:20

标签: c++ templates metaprogramming c++14 c++17

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

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的解决方案将不胜感激。

2 个答案:

答案 0 :(得分:0)

好的,我想我看了一眼:

#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首先成为其递归循环中所需位置的元素。其余的很简单,我们需要检索数据并跟踪我们的循环时间。

我会尽快为这个答案添加更多细节。

答案 1 :(得分:0)

首先,不要这样做,而是使用元组并从所述元组构造对象。

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分隔。

Live example

我使用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>{} );
}