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