【问题标题】:Split a parameter pack at a given type拆分给定类型的参数包
【发布时间】:2017-03-28 21:13:58
【问题描述】:

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

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

【问题讨论】:

  • 最好避免这种事情。也许你应该传递包含相关参数的元组,或者类似的。

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


【解决方案1】:

好的,我想我知道了,看看:

#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());
}

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

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

【讨论】:

  • 谢谢。但是,这个实现是为 foo1 实现的,参数列表已知吗?在我的许多情况下, foo1 和 foo2 可以采用可变参数。
  • 嗯,如果 foo1 和 2 都只接受可变参数呢?如果我将附加信息传递给 foo1 和 foo2,比如序列中的索引,可以吗?
【解决方案2】:

首先,不要这样做,而是获取元组并从所述元组构造您的对象。

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

无论如何我们都会去这里。

如果做不到这一点,请编写一个函数,该函数接受 std::tuple&lt;Ts...&gt; 并将其拆分为分隔符上的 std::tuple&lt; std::tuple&lt;???&gt;... &gt; 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&lt;Bob&gt;( 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>{} );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 2021-06-14
    • 2019-02-13
    相关资源
    最近更新 更多