• C++函数模板


    函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,也就是说,函数模板代表一个函数家族,这些函数的元素是未定的,在使用的时候被参数化。

    本文地址:http://www.cnblogs.com/archimedes/p/cpp-template.html,转载请注明源地址。

    下面举一个简单的例子:

    定义模板:

    template<typename T>
    inline T const& max(T const& a, T const& b)
    {
        return a < b ? b : a;
    }

    这个模板定义指定了一个“返回两个值中最大者”的函数家族,这两个值通过函数参数a , b传递给函数模板的,而参数的类型还没有确定,用模板参数T来代替。
    其中,typename可以用class来代替,但是建议使用typename

    完整代码如下:

    #include<iostream>
    #include<string>
    using namespace std;
    
    template<typename T>
    inline T const& max(T const& a, T const& b)
    {
        return a < b ? b : a;
    }
    
    int main()
    {
        int i = 42;
        cout<<"max(7, i): "<<::max(7, i)<<endl;
    
        double f1 = 3.4;
        double f2 = 5.6;
        cout<<"max(f1, f2): "<<::max(f1, f2)<<endl;
        
        string s1 = "mathematics";
        string s2 = "math";
        cout<<"max(s1, s2): "<<::max(s1, s2)<<endl;
        cin.get();  
        return 0;
    }

    实参的选择:

    模板参数可以根据我们传递的实参来决定,如果我们传递了两个int给参数类型T const&,那么C++编译器得出结论:每个T都必须正确的匹配,如果此时传递的实参为:max(4, 4.2),则出现编译错误

    有3种方法来处理上面的错误:

    1、对实参进行强制类型转换,使它们可以互相匹配:

    max(static_cast<double>(4), 4.2);

    2、显示指定(或限定)T的类型:

    max<double>(4, 4.2)

    3、指定两个参数可以具有不同的类型

     模板参数

    函数模板有2种类型的参数:

    1、模板参数:位于函数模板名称的前面,在一对尖括号内部进行声明:

    template<typename T>

    2、用参数:位于函数模板名称之后,在一对圆括号内部进行声明:

    ...max(T const& a, T const& b)

    可以声明任意数量的模板参数,在函数模板的内部,不能指定缺省的参数。

    template<typename T1, typename T2>
    inline T1 max(T1 const& a, T2 const& b)
    {
        return a < b ? b : a;
    }
    ...
    max(4, 4.2);

    可以引入第三个模板实参类型,来定义函数模板的返回类型:

    template<typename T1, typename T2, typename RT>
    inline RT max(T1 const& a, T2 const& b);
    ...
    max<int, double, double>(4, 4.2);

    行得通,但是很麻烦

    还有一种方法是只显示的指定第一个实参,而让演绎过程推导出其余的实参。

    template<typename RT, typename T1, typename T2>
    inline RT max(T1 const& a, T2 const& b);
    ...
    max<double>(1, 4.2);  //ok, 返回类型是double

     重载函数模板

    和普通函数一样,函数模板也可以被重载,示例代码如下:

    #include<iostream>
    #include<string>
    using namespace std;
    
    inline int const& max(int const& a, int const& b)
    {
        return a < b ? b : a;
    }
    
    template<typename T>
    inline T const& max(T const& a, T const& b)
    {
        return a < b ? b : a;
    }
    
    template<typename T>
    inline T const& max(T const& a, T const& b, T const& c)
    {
        return ::max(::max(a, b), c);
    }
    
    int main()
    {
        cout<<::max(7, 12, 67)<<endl;       //调用具有3个函数的模板
        cout<<::max(7.9, 34.5)<<endl;       //调用max<double>(通过实参演绎)
        cout<<::max('a', 'y')<<endl;        //调用max<char>(通过实参演绎)
        cout<<::max(7, 42)<<endl;           //调用int重载的非模板函数
        cout<<::max<>(7, 23)<<endl;         //调用max<int>(通过实参演绎)
        cout<<::max<double>(4, 45)<<endl;   //调用max<double>(没有实参演绎)
        cout<<::max('a', 23.4)<<endl;       //调用int重载的非模板函数
    
        cin.get();  
        return 0;
    }

      下面的更有用的例子将会为指针和普通的C字符串重载这个求最大值的模板:

    #include<iostream>
    #include<string>
    using namespace std;
    
    //求两个任意类型值的最大者
    template<typename T>
    inline T const& max(T const& a, T const& b)
    {
        return a < b ? b : a;
    }
    
    //求两个指针所指向值的最大者
    template<typename T>
    inline T* const& max(T* const& a, T* const& b)
    {
        return a < b ? b : a;
    }
    
    //求两个C字符串的最大者
    inline char const* const& max(char const* const& a, char const* const& b)
    {
        return *a < *b ? b : a;
    }
    
    int main()
    {
        int a, b;
        a = 7;
        b = 42;
        ::max(a, b);   //max()求两个int值的最大值
         
        string s = "hey";
        string t = "you";
        cout<<::max(s, t)<<endl;   //max()求两个string类型的最大值
    
        int* p1 = &b;
        int* p2 = &a;
        cout<<::max(p1, p2)<<endl;  //max()求两个指针所指向值的最大值
    
        char const* s1 = "Davide";
        char const* s2 = "Nico";
        cout<<::max(s1, s2)<<endl;  //max()求两个c字符串的最大值
    
        cin.get();  
        return 0;
    }

    以上在所有实现重载里面,都是通过引用来传递每个实例的,但是一般而言,在重载函数模板的时候,最好只是改变那些需要改变的内容,应该把改变限制在以下两个方面:

    改变参数的数目或显式地指定模板参数

     对于以上的重载,如果改为基于C-string的max()函数,通过传值来传递参数,就不能实现3个参数的max()版本:

    #include<iostream>
    #include<string>
    using namespace std;
    
    //求两个任意类型值的最大者(通过传引用进行调用)
    template<typename T>
    inline T const& max(T const& a, T const& b)
    {
        return a < b ? b : a;
    }
    
    //求两个C字符串的最大者(通过传值进行调用)
    inline char const* max(char const* a, char const* b)
    {
        return strcmp(a, b) < 0 ? b : a;
    }
    
    //求3个任意类型值的最大者(通过传引用进行调用)
    template<typename T>
    inline T const& max(T const& a, T const& b, T const& c)
    {
        return max(max(a, b), c);
    }
    
    
    int main()
    {
        cout<<::max(7, 42, 68)<<endl; //ok
    
        const char* s1 = "frederic";
        const char* s2 = "anica";
        const char* s3 = "lucas";
        cout<<::max(s1, s2, s3)<<endl; //error
    
        cin.get();  
        return 0;
    }

    错误在于:如果对3个C-string调用max,则语句return max(max(a, b), c);将产生错误

    原因是对于C-string而言,max(a, b)产生了一个新的临时局部值,该值有可能被外面的max函数以传引用的方式返回,将导致传回无效的引用。

     

     

  • 相关阅读:
    spring(二) AOP之AspectJ框架的使用
    spring(一) IOC讲解
    struts2(六) 文件上传和下载
    导入Excel后绑定GridView实例
    类型“GridView”的控件必须放在具有 runat=server 的窗体标记内?
    只能在执行 Render() 的过程中调用 RegisterForEventValidation
    C# 连接SQL Server数据库的几种方式--server+data source等方式
    C#未将对象引用设置到对象的实例
    代码保存好
    在选定的数据源上未找到名为“TitleSub”的字段或属
  • 原文地址:https://www.cnblogs.com/wuyudong/p/cpp-template.html
Copyright © 2020-2023  润新知