上篇中,我們實現了一個支持 R () 型函數的 Function。補充說明一下,在我們對成員函數的支持中,我們是這樣定義的:
template <typename R, typename T>
class MemberFunction0 : public FunctionBase0<R>
{
private:
R (T::*m_pMemFun)();
T *m_pObj;
};
Loki 特意在著作中提醒我們,這裡的 T 最好不要是函數類型,改為函數指針類型,如此該類的支持范圍將擴大。如下:
template <typename R, typename P, typename T>
class MemberFunction0 : public FunctionBase0<R>
{
public:
R Invoke()
{
return (m_pObj->*m_pMemFun)();
}
public:
MemberFunction0(P pObj, R (T::*pMemFun)())
: m_pObj(pObj), m_pMemFun(pMemFun)
{
}
private:
R (T::*m_pMemFun)();
P m_pObj;
};
於是,P 和 T 的關系不那麼緊密了,P 不一定非要 T* 不可,也可以是諸如 SmartPtr<T> 之類的玩意兒。原本只支持傳入一個對象和該對象的成員函數的,現在變成傳入一個具有指針概念的東東和一個成員函數,只要這個“指針”使用運算符 –> 去調用那個成員函數合乎語法即可。
接下來,我們來擴展這個 Function,以支持擁有數目在給定上限內的任意參數的函數。
我們先來手工寫一下,看看如何支持帶一個參數的函數。首先定義一個虛基類:
template <typename R, typename T0>
class FunctionBase1
{
public:
virtual R Invoke(T0) = 0;
virtual ~FunctionBase1() {}
};
實現兩個版本,分別支持非成員函數和成員函數:
template <typename R, typename T0, typename T>
class Function1 : public FunctionBase1<R, T0>
{
public:
R Invoke(T0 v0)
{
return m_Fun(v0);
}
public:
Function1(const T &fun)
: m_Fun(fun)
{
}
private:
T m_Fun;
};
template <typename R, typename P, typename T, typename T0>
class MemberFunction1 : public FunctionBase1<R, T0>
{
public:
R Invoke(T0 v0)
{
return (m_pObj->*m_pMemFun)(v0);
}
public:
MemberFunction1(P pObj, R (T::*pMemFun)(T0))
: m_pObj(pObj), m_pMemFun(pMemFun)
{
}
private:
R (T::*m_pMemFun)(T0);
P m_pObj;
};
增加一個函數引用萃取的偏特化版本:
template <typename RetType, typename T0>
struct FunctionTraits<RetType (T0)>
{
typedef RetType (&ParamType)(T0);
};
增加一個 Function 類的偏特化版本:
template <typename R, typename T0>
class Function<R (T0)>
{
public:
template <typename T>
Function(const T &fun)
: m_pFunBase(new Function1<R, T0, typename FunctionTraits<T>::ParamType>(fun))
{
}
template <typename P, typename T>
Function(P pObj, R (T::*pMemFun)(T0))
: m_pFunBase(new MemberFunction1<R, P, T, T0>(pObj, pMemFun))
{
}
~Function()
{
delete m_pFunBase;
}
R operator ()(T0 v0)
{
return m_pFunBase->Invoke(v0);
}
private:
FunctionBase1<R, T0> *m_pFunBase;
};
現在,我們可以跑一下測試代碼了:
Function<int (int)> f1(&intfun1);
Function<int (int)> f1_(intfun1);
Function<int (int)> f2(intfunctor1);
Function<int (int)> f3(&test, &Test::intmem1);
f1(1);
f1_(1);
f2(2);
f3(3);
當然,void 函數也是支持的。
觀察上面的這些代碼,和我們在上一篇中的代碼高度一致,不同的是那些模版參數、偏特化參數、函數調用參數等地方。
假如有這麼一組宏:
TYPENAME_DECLARE(n) 被定義為 typename T0, typename T1, …, typename Tn
TYPENAME_LIST(n) 被定義為 T0, T1, …, Tn
TYPENAME_VARIABLE(n) 被定義為 T0 v0, T1 v1, …, Tn vn
VARIABLE_LIST(n) 被定義為 v0, v1, …, vn
那麼我們可以使用一個 n 就寫出支持所有具有參數的函數的 Function 了。我們拋棄掉上面的 1 系列的所有類,僅保持上篇留下來的代碼,然後利用上面 4 個宏將所有數字尾巴去掉,於是代碼變成:
template <typename R, TYPENAME_DECLARE(n)>
class FunctionBase_##n
{
public:
virtual R Invoke(TYPENAME_LIST(n)) = 0;
virtual ~FunctionBase_##n() {}
};
template <typename R, TYPENAME_DECLARE(n), typename T>
class Function_##n : public FunctionBase_##n<R, TYPENAME_LIST(n)>
{
public:
R Invoke(TYPENAME_VARIABLE(n))
{
return m_Fun(VARIABLE_LIST(n));
}
public:
Function_##n(const T &fun)
: m_Fun(fun)
{
}
private:
T m_Fun;
};
template <typename R, typename P, typename T, TYPENAME_DECLARE(n)>
class MemberFunction_##n : public FunctionBase_##n<R, TYPENAME_LIST(n)>
{
public:
R Invoke(TYPENAME_VARIABLE(n))
{
return (m_pObj->*m_pMemFun)(VARIABLE_LIST(n));
}
public:
MemberFunction_##n(P pObj, R (T::*pMemFun)(TYPENAME_LIST(n)))
: m_pObj(pObj), m_pMemFun(pMemFun)
{
}
private:
R (T::*m_pMemFun)(TYPENAME_LIST(n));
P m_pObj;
};
template <typename RetType, TYPENAME_DECLARE(n)>
struct FunctionTraits<RetType (TYPENAME_LIST(n))>
{
typedef RetType (&ParamType)(TYPENAME_LIST(n));
};
template <typename R, TYPENAME_DECLARE(n)>
class Function<R (TYPENAME_LIST(n))>
{
public:
template <typename T>
Function(const T &f