现在,我们想实现一个元函数,可以返回char类型指定层数的指针类型。
template<int N>
struct CharPointer
{
using Result = typename Times<N, char, PointerOf>::Result;
};
如上,我们定义了元函数CharPointer,它是一个int型单参元函数。它的实现调用了Times,将其第二和第三个参数分别固定为char和PointerOf。
借助于继承的特性,上面的代码可以简化为:
template<int N>
struct CharPointer :Times<N, char, PointerOf>
{
};
这种定义元函数的方式叫做元函数转发。
如果借助using关键字,可以实现得更加简单:
template<int N> using CharPointer = Times<N, char, PointerOf>;
这里我们直接对Times绑定第二和第三个参数后为其起了别名CharPointer。
在函数式编程里面,有个概念叫做函数柯里化(currying),是指一个函数接收部分参数后,并不立即求值,而是继续返回另一个函数。
如下Haskell代码定义了一个三数相乘的函数multiThree,它接收三个Int型参数返回它们的乘积:
multiThree :: Int -> Int -> Int -> Int
multiThree x y z = x * y * z
当我们将multiThree其中一个参数固定后,它就变成了一个二参函数。
ghci > let multiTwoWithNine = multiThree 9
ghci > multiTwoWithNine 2 3
我们使用using关键字实现元函数转发,可以达到类似函数柯里化的效果。柯里化可以帮助更容易地复用函数,实现函数之间更低成本且更灵活的组合。
函数柯里化在函数式编程语言里的意义非常重要,和C++模板元编程里面的还是有区别的。例如在Haskell中,可以不用为柯里化函数定义别名,就直接将其作为另一个函数的参数传递,而在C++模板元编程里目前还做不到。
现在借助柯里化,我们重新实现Pointer2Of如下:
template<typename T> using Pointer2Of = Times<2, T, PointerOf>;
可以看到,所谓的Pointer2Of,其实就是把Times的第一个和第三个参数固定后,得到的单参柯里化函数。
网友评论