接著上面的例子,此刻我們想要定義指向指針的指針的指針的指針類型,怎么辦?或者說我們想要一種能夠任意指定指針層數(shù)的元函數(shù)。
如果我們想復(fù)用手里已有的PointerOf元函數(shù)來完成,我們就需要有一個能夠?qū)ointerOf反復(fù)施展指定次數(shù)的元函數(shù)。
下面我們實現(xiàn)了一個通用的Times元函數(shù),它可以對一個指定類型T反復(fù)調(diào)用另一個元函數(shù)N次。
template<int N, typename T, template<typename> class Func>
struct Times
{
using Result = typename Func<typename Times<N - 1, T, Func>::Result>::Result;
};
template<typename T, template<typename> class Func>
struct Times<1, T, Func>
{
using Result = typename Func<T>::Result;
};
上面的代碼中,Times有三個參數(shù),第一個參數(shù)是次數(shù)N,第二個參數(shù)是類型T,第三個參數(shù)是可以接收一個類型參數(shù)的元函數(shù)Func。Times采用了遞歸實現(xiàn),當(dāng)N為1時,Result就是元函數(shù)Func的結(jié)果,否則就遞歸調(diào)用Func<typename Times<N - 1, T, Func>::Result>::Result
。
最后我們通過組合兩個元函數(shù),實現(xiàn)了計算指定類型的四層指針類型,如下:
int*** pppi;
Times<4, int, PointerOf>::Result ppppi = &pppi;
上面的Times元函數(shù)是一個可以接收一個元函數(shù)做參數(shù)的元函數(shù),在函數(shù)式編程里面這稱作高階函數(shù)。高階函數(shù)可以讓代碼在更高的抽象層次上進行組合復(fù)用。
比如我們同樣可以可以將Pointer2Of和Times組合起來,實現(xiàn)四重指針類型計算:
int*** pppi;
Times<2, int, Pointer2Of>::Result ppppi = &pppi;
事實上有了Times元函數(shù),我們可以輕易得到任意層數(shù)的指針類型。
using Pointer3OfInt = typename Times<3, int, PointerOf>::Result;
int** ppi;
Pointer3OfInt pppi = &ppi;
高階函數(shù)除了允許函數(shù)的參數(shù)是函數(shù),還允許函數(shù)的返回值也是函數(shù)。對于C++,我們利用可以在類或者模板里面嵌套定義模板的特性,來實現(xiàn)元函數(shù)的返回值是元函數(shù)。
template<typename T>
struct OuterFunc
{
template<typename U, typename V>
struct Result
{
// ...
};
};
如上我們定義了一個單參元函數(shù)OuterFunc
,它的返回值是另外一個雙參元函數(shù)。注意,在調(diào)用類或模板內(nèi)部定義的模板時,標準要求必須使用template關(guān)鍵字。所以我們這樣使用OuterFunc的返回值函數(shù):OuterFunc<int>:: template Result
。
由于C++標準不允許在類或者模板的內(nèi)部定義模板的特化,一旦我們定義的內(nèi)部元函數(shù)使用了模板特化,那么就必須定義在外面,再由原來的外層元函數(shù)引用。如下:
template<typename T, typename U>
struct InnerFunc
{
// 主版本實現(xiàn)
};
template<typename T>
struct InnerFunc<T, T>
{
// 特化版本實現(xiàn)
};
template<typename T>
struct OuterFunc
{
template<typename U, typename V>
using Result = InnerFunc<U, V>;
};