| template<typename R, typename T1> class function<R(T1)> { R operator()(T1 a1); }; template<typename R, typename T1, typename T2> class function<R(T1, T2)> { R operator()(T1 a1, T2 a2); }; template<typename R, typename T1, typename T2, typename T3> class function<R(T1, T2, T3)> { R operator()(T1 a1, T2 a2, T3 a3); }; … // 再写下去页宽不够了,打住… |
如此一共N(N由一个宏控制)个版本。
这种做法有两个问题:一,函数的参数个数始终还是受限的,您作出N个特化版本,那么对N 1个参数的函数就没辙了。boost::tuple也是这个问题。二,代码重复。每个特化版本里面除了参数个数不同之外基本其他都是相同的;boost解决这个问题的办法是利用宏,宏本身的一大堆问题就不说了,您只要打开boost.function的主体实现代码就知道有多糟糕了,近一千行代码,其中涉及元编程和宏技巧无数,可读性能够说基本为0。好在这是个标准库(boost.function将加入tr1)不用您维护,假如是您自己写了用的库,恐怕除了您谁也别想动了。所以第二个问题其实就是可读性可维护性问题,用Matthew Wilson的说法就是可发现性和透明性的问题,这是个很严重的问题,许多C 现代库因为这个问题而遭到诟病。
现在,让我们来看一看加入了variadic templates之后的C 09实现:
| template<typename R, typename... Args> struct invoker_base { virtual R invoke(Args...) = 0; virtual ~invoker_base() { } }; template<typename F, typename R, typename... Args> struct functor_invoker : public invoker_base<R, Args...> { explicit functor_invoker(F f) : f(f) { } R invoke(Args... args) { return f(args...); } private: F f; }; template<typename Signature> class function; template<typename R, typename... Args> class function<R (Args...)> { public: template<typename F> function(F f) : invoker(0) { invoker = new functor_invoker<F, R, Args...>(f); } R operator()(Args... args) const { return invoker->invoke(args...); } private: invoker_base<R, Args...>* invoker; }; |
整个核心实现就这些!一共才36行!加上析构函数拷贝构造函数等边角料一共也就70行!更重要的是,整个代码清楚无比,任何涉及到可变数目个模板参数的地方都由variadic templates代替。“Args…”恰如其分的表达了我们想要表达的意思——多个参数(数目不管)。和C 98的boost.function实现真是天壤之别!
[1] [2] [3] [4] [5]



