如何为模板方法实现编译时foreach()?

时间:2013-11-21 20:44:11

标签: c++ templates template-meta-programming

我想实现一个编译时foreach(),它可以调用给定的模板成员函数N次。 目前我有编译时的foreach:

struct ForEach
{
   template <size_t Dummy>
   struct IntToType {};

   typedef IntToType<true> ForEachDoNotTerminateLoop;
   typedef IntToType<false> ForEachTerminateLoop;

   template <size_t TIdx, size_t TCount, typename TMethod>
   static void ForEachImpl(ForEachDoNotTerminateLoop, TMethod method)
   {
      method.Invoke<TIdx>();
      ForEachImpl<TIdx + 1, TCount, TMethod>(Internal::IntToType<(TIdx + 1 < TCount)>(), method);
   }

   template <size_t TIdx, size_t TCount, typename TMethod>
   static void ForEachImpl(ForEachTerminateLoop, TMethod method)
   {
   }

   template <size_t TCount, typename TMethod>
   static void Member(TMethod method)
   {
      ForEachImpl<0, TCount, TMethod>(Internal::IntToType<(0 < TCount)>(), method);
   }
};

还有一些模板类:

template <typename T, size_t TCount>
class SomeClass
{
public:
   void Foo(int arg1)
   {
      ForEach::Member<TCount>(BarInvoker(this, arg1));
   }

private:
   struct BarInvoker // <-- How can I make this invoker a template to make it more flexible?
   {
      BarInvoker(SomeClass* instance, int arg1)
         : instance(instance)
         , arg1(arg1)
      {}

      template <size_t N>
      void Invoke()
      {
         instance->Bar<N>(arg1);
      }

      int arg1;
      SomeClass* instance;
   };

   template <size_t N>
   void Bar(int arg1)
   {
      _data[N] = arg1;
   }

   int* _data;
   T* _otherData;
};

有没有办法绕过“调用者”仿函数,使其更灵活(模板)并更容易使用? 我真的不喜欢通过为每个私有成员函数添加“调用者”存根来膨胀我的代码。 只需拨打ForEach::Member<TCount, int>(Bar, 5);

即可

先谢谢你帮我解决这个模板的怪异! :)

1 个答案:

答案 0 :(得分:4)

在类中包装模板函数并将类的实例传递给ForEach :: Call&lt;&gt;用任意参数来调用它,似乎是一个相当干净的解决方案。

ForEach::Call<>的调用如下:ForEach::Call<N>(function_object, arguments...)

function_object是一个定义为operator()的类:

template <std::size_t Idx>  // Current index in the for-loop.
void operator()(/* arguments... */) { /* Impl. */ }

这是我的ForEach&lt;&gt;版本。

class ForEach {
  public:

  /* Call function f with arguments args N times, passing the current index
     through the template argument. */
  template <std::size_t N, typename F, typename... Args>
  static void Call(F &&f, Args &&...args) {
    Impl<0, N>()(std::forward<F>(f), std::forward<Args>(args)...);
  }

  private:

  /* Forward declaration. */
  template <std::size_t Idx, std::size_t End>
  class Impl;

  /* Base case. We've incremeneted up to the end. */
  template <std::size_t End>
  class Impl<End, End> {
    public:

    template <typename F, typename... Args>
    void operator()(F &&, Args &&...) { /* Do nothing. */ }

  };  // Impl<End, End>

  /* Recursive case. Invoke the function with the arguments, while explicitly
     specifying the current index through the template argument. */
  template <std::size_t Idx, std::size_t End>
  class Impl {
    public:

    template <typename F, typename... Args>
    void operator()(F &&f, Args &&...args) {
      std::forward<F>(f).template operator()<Idx>(std::forward<Args>(args)...);
      Impl<Idx + 1, End>()(std::forward<F>(f), std::forward<Args>(args)...);
    }

  };  // Impl<Idx, End>

};  // ForEach

我写了类似于你的SomeClass的东西,以证明它的用途。

template <std::size_t Size>
class Ints {
  public:

  using Data = std::array<int, Size>;

  /* Call Assign, Size times, with data_ and n as the arguments. */
  void AssignAll(int n) { ForEach::Call<Size>(Assign(), data_, n); }

  /* Call Print, Size times, with data_ and n as the arguments. */
  void PrintAll() const { ForEach::Call<Size>(Print(), data_); }

  private:

  /* Wraps our templated assign function so that we can pass them around. */
  class Assign {
    public:

    template <size_t N>
    void operator()(Data &data, int arg) const {
      data[N] = arg;
    }

  };  // Assign

  /* Wraps our templated print function so that we can pass them around. */    
  class Print {
    public:

    template <size_t N>
    void operator()(const Data &data) const {
      std::cout << data[N] << std::endl;
    }

  };  // Print

  /* Our data. */
  Data data_;

};  // Ints<Size>

Ints类的简单用例。

int main() {
  Ints<5> ints;
  ints.AssignAll(101);
  ints.PrintAll();
}

打印:

101
101
101
101
101