C ++中的任意数量的块的lambda函数可伸缩的分组(c++ scalable grouping

2019-09-28 03:12发布

我必须执行几个lambda函数,但每次每个N lambda表达式一个prologue()函数也必须运行。 lambda表达式的数量可以是任意大和N在编译时已知的。 事情是这样的:

static void prologue( void )
{
    cout << "Prologue" << endl;
}

int main()
{
    run<3>( // N = 3
        [](){ cout << "Simple lambda func 1" << endl; },
        [](){ cout << "Simple lambda func 2" << endl; },
        [](){ cout << "Simple lambda func 3" << endl; },
        [](){ cout << "Simple lambda func 4" << endl; },
        [](){ cout << "Simple lambda func 5" << endl; },
        [](){ cout << "Simple lambda func 6" << endl; },
        [](){ cout << "Simple lambda func 7" << endl; }
    );
}

输出:

Prologue
Simple lambda func 1
Simple lambda func 2
Simple lambda func 3
Prologue
Simple lambda func 4
Simple lambda func 5
Simple lambda func 6
Prologue
Simple lambda func 7
End

剩下的人必须妥善处理。

我已经得出了以下的解决方案,但你可以看到,因为我写的每一个处理程序是不是很可扩展N

它可以做一些神奇的元编程,以涵盖所有可能N ? 难道我失去焦点,有一个完全不同的方法来解决这个问题? 一切都必须在编译时得到解决。

#include <iostream>    
using namespace std;

static void prologue( void );

// Primary template
template< int N, typename... Args>
struct Impl;

// Specialitzation for last cases
template< int N, typename... Args >
struct Impl
{
    static void wrapper( Args... funcs )
    {
        Impl<N-1, Args...>::wrapper( funcs... );
    }
};

// Specilitzation for final case
template<int N>
struct Impl<N>
{
    static void wrapper( )
    {
        cout << "End" << endl;
    }
};

template< typename Arg1, typename... Args >
struct Impl<1, Arg1, Args...>
{
    static void wrapper( Arg1 func1, Args... funcs )
    {
        prologue();
        func1();

        Impl<1, Args...>::wrapper( funcs... );
    }
};

template< typename Arg1, typename Arg2, typename... Args >
struct Impl<2, Arg1, Arg2, Args...>
{
    static void wrapper( Arg1 func1, Arg2 func2, Args... funcs )
    {
        prologue();
        func1();
        func2();

        Impl<2, Args...>::wrapper( funcs... );
    }
};

template< typename Arg1, typename Arg2, typename Arg3, typename... Args >
struct Impl<3, Arg1, Arg2, Arg3, Args...>
{
    static void wrapper( Arg1 func1, Arg2 func2, Arg3 func3, Args... funcs )
    {
        prologue();
        func1();
        func2();
        func3();

        Impl<3, Args...>::wrapper( funcs... );
    }
};

// Static class implementation wrapper
template< int N, typename... Args >
static void run( Args... funcs )
{
    Impl<N, Args...>::wrapper( funcs... );
}

编辑 :发布一个相关的问题 。

Answer 1:

一个简单的办法

template <std::size_t N, typename ... Ts>
void run (Ts const & ... fn)
 {
   using unused = int[];

   std::size_t  i { N-1U };

   (void)unused { 0, ( (++i % N ? 0 : (prologue(), 0)), (void)fn(), 0)... };
 }

-编辑-添加(void)在前面的号召fn()以避免在Yakk注释解释逗号劫持招(谢谢!)。



Answer 2:

怎么样使用辅助结构?

template <std::size_t N, std::size_t M>
struct runH
 {
   template <typename T0, typename ... Ts>
   static void func (T0 const & f0, Ts const & ... fn)
    {
      f0();
      runH<N, M-1U>::func(fn...);
    }

   static void func ()
    { }
 };

template <std::size_t N>
struct runH<N, 0>
 {
   template <typename ... Ts>
   static void func (Ts const & ... fn)
    {
      if ( sizeof...(fn) )
         prologue();

      runH<N, N>::func(fn...);
    }
 };

template <std::size_t N, typename ... Ts>
void run (Ts const & ... fn)
 { runH<N, 0>::func(fn...); }


Answer 3:

Preable:

将一个函数对象。 返回一个函数对象,需要许多指定参数时,将它们一次一个的第一个对象。

template<class F>
void foreach_arg(F&&f){
  return [f=std::forward<F>(f)](auto&&...args){
    using discard=int[];
    (void)discard{0,(0,void(
      f(decltype(args)(args))
    ))...}
  };
}

然后,我们只是跟踪指数:

template<std::size_t N, class...Args>
void run(Args&&...args){
  std::size_t i = 0;
  foreach_arg([&](auto&&arg){
      if (!(i%N))prologue();
      ++i;
      arg();
    }
  )( args... );
}

一个更复杂的解决方案。 它计算指数为constexpr值。

首先,从我们一包第n ARG:

template<std::size_t N, class...Args>
decltype(auto) nth(Args&&...args){
  return std::get<N>(std::forward_as_tuple(std::forward<Args>(args)...));
}

取的索引序列。 返回取一个函数对象的功能,然后传递该对象编译时间索引:

template<std::size_t...Is>
auto index_over(std::index_sequence<Is...>){
  return [](auto&&f)->decltype(auto){
    return decltype(f)(f)(std::imtegral_constant<std::size_t,Is>{}...);
  };
}

让你调用上述0...N-1这是常见的情况:

template<std::size_t N>
auto index_upto(std::integral_constant<std::size_t,N> ={}){
  return index_over(std::make_index_sequence<N>{});
}

现在,实际的问题,具体的代码:

template<std::size_t N, class...Args>
void run(Args&&...args){
  index_upto<sizeof...(Args)>()(
    foreach_arg([&](auto I){
      if (!(I%N))prologue();
      nth<I>(std::forward<Args>(args)...)(); 
    })
  );
}

有可能是tpyos。

这其中也可编译较慢; 它产生为O(n ^ 2)的代码。



文章来源: c++ scalable grouping of lambda functions in blocks of an arbitrary number