全局函数指针做为模板参数

  • 一样,函数指针型模板参数的意义在于:在变与不变之间取得最优实现。一般函数指针的做用是实现回调(callback),即由调用方将所须要操 做包装成某个函数f0,并将指向此函数的指针&f0做为参数传递给函数f1。函数f1在运行时回调所指函数f0,从而实现调用方所期待操做。f0 就是一个回调函数。将回调函数指针做为被调用函数的参数时,实现的是动态回调,只有在运行时才能肯定是回调哪一个函数。若是并不须要动态回调,只为方便,在 已有算法框架中嵌入所需操做,则动态回调就略显牛刀杀鸡。此时,将回调函数指针从函数参数移到模板参数,就很容易实现“静态回调”。ios

    注意 之因此在“静态回调”上加引号,是由于其并不能算作严格的“回调”。回调函数指针是在编译时给定,在模板实例中,就至关于将本来用指针进行回调的地方用所给函数代替,成为彻底普通的函数调用。这样也节省了一点点读取指针值肯定函数入口的额外运行开销。算法

    例3.1虽然看起来有些古怪,却演示了函数指针型模板参数的用法。假设对某一数组,须要先依次打印数组元素,依次将元素加1,依次打印,依次将元素减1,再依次打印。数组

    之因此强调“依次”,是由于对于数组及其余任何序列来讲,“依次”操做是一种最多见的需求。但很遗憾,不管C或者C++,都未将“依次”做为内建支 持。每次都用for循环语句来遍历数组当然可行,却会使代码看起来冗长。更好的作法是将“依次”抽象成可复用代码,好比一个foreach函数,再将对数 组元素所作操做包装成一个回调函数,并将其指针传入foreach函数便可。当操做有限且已知时,显然应该将函数指针从foreach函数参数移至模板参 数实现“静态回调”。了解用意后,就不难理解例3.1的代码了。框架

    例3.1
    #include <iostream>函数

    // 定义一个foreach函数模板,对数组的每个元素进行某种操做
    // 具体操做由模板的函数指针参数指定
    template<typename T, void (*f)(T &v)>
    void foreach(T array[], unsigned size)
    {
        for (unsigned i = 0; i < size; ++i) f(array[i]);
    }spa

    // 三个函数模板用来定义对数组元素的操做
    template<typename T>
    void inc(T &v) {++v;}指针

    template<typename T>
    void dec(T &v) {--v;}回调函数

    template<typename T>
    void print(T &v) {std::cout << ' ' << v;}io

    int main()
    {
        int array[] = {1, 2, 3, 4, 5, 6, 7, 8};for循环

        using namespace std;
        foreach<int, print<int> >(array, 8);
        cout << endl;

        foreach<int, inc<int> >(array, 8);
        foreach<int, print<int> >(array, 8);
        cout << endl;

        foreach<int, dec<int> >(array, 8);
        foreach<int, print<int> >(array, 8);
        cout << endl;

        return 0;
    }

    例3.1中,foreach定义为一个函数模板,其第二个模板参数是一个函数指针。因为模板参数必须在编译时给定,因此这个foreach函数实现 了“静态回调”。另有一个值得注意的是,第二个模板参数void(*f)(T*v)的定义中用到第一个模板参数T。这是合法的,在模板参数列表中,所声明 模板参数可当即用于定义随后的模板参数。在本例中,void (*f)(T*v)约束指针型模板参数f所指函数只能接受与前一模板参数类型相同的指针参数,随后所定义的三个函数模板都是要对数据元素进行的操做,分别 是对元素值加一、减1以及打印。在main函数中则调用foreach函数模板,静态绑定对数组每一个元素分别加一、减1以及打印。

相关文章
相关标签/搜索