瘦身前後——兼談C++語言進化(4)
(3)boost採用的辦法也是C 98的辦法,就是爲不同蓡數個數的Signature進行特化:
template
class function
{
R operator()(T1 a1);
};
template
class function
{
R operator()(T1 a1, T2 a2);
};
template
class function
{
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
struct invoker_base {
virtual R invoke(Args...) = 0;
virtual ~invoker_base() { }
};
template
struct functor_invoker : public invoker_base
{
explicit functor_invoker(F f) : f(f) { }
R invoke(Args... args) { return f(args...); }
private:
F f;
};
template
class function;
template
class function
{
public:
template
function(F f) : invoker(0)
{
invoker = new functor_invoker(f);
}
R operator()(Args... args) const
{
return invoker->invoke(args...);
}
private:
invoker_base* invoker;
};
0條評論