C++: Variadic Template and Fold Expression are Powerful.

这两天做一个Pipeline的Framework,见识了现在C++ Generic Programming 的强大功能,比原来的 Object Oriented Programming 看上去 Cool 多了:完全没有关系的一堆类型,一样可以放在框架里操作,写出来的程序也没有任何效率的损失,看来这些年C++又进步了很多。下面简要说说我的设计。

Class BaseData 表示 Pipeline 中的一个数据节点。 Class Phase 表示针对数据的某个操作。 Phase 接受一些 BaseData 作为输入,并输出到另外一些BaseData。为了灵活和简单起见,Phase 不设任何 Virtual Method 作为接口,只要就实现一个 Run Method 即可。程序概要如下:

class BaseData {
public:
 get() ...
 set() ...
};

class DataA : public BaseData {...};
class DataB : public BaseData {...};
class DataC : public BaseData {...};
class DataD : public BaseData {...};

class Phase {};

class PhaseA : public Phase {
  void Run(DataA*, DataB*, DataC*) {...}
};
class PhaseB : public Phase {
void Run(DataC*, DataD*) {...}
};

class Pipeline {
private:
  DataA a_;
  DataB b_;
  DataC c_;
  DataD d_;

public:
  Run() {
    AddPhase(new PhaseA(), &a_, &b_, &c);
    AddPhase(new PhaseB(), &c_, &d_);
  }

  void AddData(BaseData* base_data) {
     ...
  }

  // This is variadic template.
  template<typename PhaseType, typename... Types>
  AddPhase(PhaseType* phase, Types args...) {

    // This is fold expression, avoid template recursion.
    (..., AddData(args));

    // This is variadic forward.
    std::function<void()> run = 
        std::bind(&PhaseType::Run, phase, args...);
  }
};

程序的精妙全在最后的AddPhase 这个函数,它首先通过一个 Variadic Template 来处理任意接口的函数,然后又通过一个 Fold Expression 对所有的数据进行了类型检查和处理,最后又使用 variadic forward 创建了一个 Closure 供以后调用,真是妙不可言啊。

在做了若干后续改进之后,今天终于在Team Meeting 上把这个东西讲出去了,心头考虑了大半年的东西终于一朝做出,真是很开心。 🙂