• C++学习笔记35:函数模板


    函数模板

    函数模板的目的

    • 设计通用的函数,以适应广泛的数据型式

    函数模板的定义格式

    • template<模板型式参数列表>返回值型式 函数名称(参数列表);
    • 原型:template<class T> void Swap(T &a, T&b);
    • 实现:template<class T> void Swap(T &a , T&b){...}

    函数模板的体化与特化

    • 针对特定型参数,在声明或第一次调用该函数模板时体化
    • 每次体化都形成针对特定型参数的重载函数版本
    • 文件最终只保留特定型参数的一份体化后的函数
    • 显式体化主要用于库的设计;显式特化覆盖体化的同型函体

    //函数模板

    template<class T> void f(T t) {/* */}

    //显式体化:使用显式的长整型模板参数

    template void f<long>(long n);

    //显式体化:使用d的型式推导模板参数型式

    template void f(double d);

    //显式特化:使用显式的整型参数

    template<>  void f<int> (int n);

    //显式特化:使用c的型式推导模板参数型式

    template<> void f(char c);

    template <class T> void Swap(T &a, T &b)
    {
        T a; t = a, a = b, b = t;
    }
    int main()
    {
        int m = 11, n = 7;
        char a = 'A', b = 'B';
        double c = 1.0, d = 2.0;
        //正确调用,体化Swap(int &,int &)
        Swap(m, n);
        //正确调用,体化Swap(char &,char &)
        Swap<char>(m, n);
        //正确调用,体化Swap(double &, double &)
        Swap<double>(c, d);
        return 0;
    }

    函子

    编写函数,求某个数据集的最小元,元素型式为T

    • 实现策略:使用函数指针作为回调函数参数
    • 实现策略:使用函子(function object, functor)作为回调函数参数

    函数指针实现

    //const T *a 指向数据集的基地址
    //n为元素的个数
    template<typename T>
    const T &Min(const T *a, int n, bool(*compare)(const T&, const T&))
    {
        int index = 0;
        for (int i = 1; i < n; i++)
        {
            if (comparer(a[i], a[index]))
                index = i;
        }
        return a[index];
    }

    函子

    函子的目的

      功能上:类似函数指针

      实现上:重载函数调用操作符,必要时重载小于比较操作符

    函子的优点

      函数指针不能内联,而函子可以,效率更高

      函子可以拥有任意数量的额外数据,可以保证结果和状态,提高代码的灵活性

      编译时可对函子进行型式检查

    函子实现

    //使用方法

    int a[8] = {9,2,3,4,5,6,7,8};

    int min = Min(a,8,Comparer<int>());//构造匿名函子作为函数参数

    template<typename T>class Comparer
    {
    public:
        //确保型式T已存在或重载operator<
        bool operator()(const T &a, const T &b)
        {
            return a < b;
        }
    };
    
    template<typename T,typename Comparer>
    const T &Min(const T *a, int n, Comparer comparer)
    {
        int index = 0;
        for (int i = 1; i < n; i++)
        {
            if (comparer(a[i], a[index]))
                index = i;
        }
        return a[index];
    }

    完美转发

    完美转发的意义

    • 库的设计者需要设计一个通用的函数,将接受到的参数转发给其他函数
    • 转发过程中,所有参数保持原先的语义不变

    完美转发的实现策略

    • 当需要同时提供移动语义和拷贝语义时,要求重载大量建构函数,编程量大,易出错
    • 右值引用与函数模板相互配合,可以实现完美转发,极大降低代码编写量

    例子:

    class A
    {
    public:
        A(const string &s, const string &t) :_s(s), _t(t) {}
        A(const string &s, string && t) :_s(s), _t(move(t)) {}
        A(string &&s, const string &t) :_s(move(s)), _t(t) {}
        A(string &&s, string &&t) :_s(move(s)), _t(move(t)) {}
    private:
        string _s, _t;
    };
    int main()
    {
        string s1("Hello");
        const string s2("World");
        A a1(s1, s2);
        A a3(string("Good"), s2);
        A a2(s1, string("Bingo"));
        A a4(string("Good"), string("Bingo"));
        return 0;
    }

    改进后:

    class A
    {
    public:
        //根据实际参数型式生成不同的左值或右值引用的建构函数版本
        //T1或T2可以不同型,此处相同仅为示例
        //实参推演时,使用引用折叠机制
        //当形式参数为T&&型时,当且仅当实际参数为右值或者右值引用时
        //实际参数型式才为右值引用
        //引用折叠机制与const/volatile无关,保持其参数性质不变
        //std::forward<T>(t)转发参数的右值引用T&&
        template<typename T1, typename T2> A(T1 &&s, T2 &&t)
            :_s(std::forward<T1>(s)), _t(std::forward<T2>(t)) {}
    private:
        std::string _s, _t;
    };
    怕什么真理无穷,进一寸有一寸的欢喜。---胡适
  • 相关阅读:
    Django之ModelForm组件
    Hibernate的继承映射
    hibernate的检索策略
    Hibernate的多对多映射关系
    Hibernate中的一对一映射关系
    Hibernate中双向的一对多关系
    Hibernate中的映射关系(一对多)
    Hibernate的映射组成关系
    Hibernate的大对象映射
    hibernate的日期映射
  • 原文地址:https://www.cnblogs.com/hujianglang/p/6260741.html
Copyright © 2020-2023  润新知