• C++中的函数模板


    一、学习笔记

    1.函数模板的定义
    template<类型参数表>
    返回值 函数名(数据参数表) {
      函数模板定义体;
    }

    eg:
    template<typename T>
    T& mymax(T& a, T& b) {
        return (a < b) ? b : a;
    }

    作用:数模板可以使相似的代码重复使用,使用类型作为参数。

    2.函数模板的使用
    (1)函数模板只是编译指令,一般写在头文件中;
    (2)编译程序时,编译器根据函数的参数来“推导”模板的参数, 然后生成具体的模板函数
    示例代码:
    int a; int b; mymax(a, b);编译器根据函数参数a,b推导出模板参数为int,所以把模板中的T绑定为int, 编译程序时生成如下函数:
    int& mymax(int& a, int& b) {
    return (a < b) ? b : a;
    }


    3.参数推导过程
    (1)有限的类型转换
    函数模板只支持下面2种隐式类型转换:
    ① const转换:函数参数为非const引用/指针, 它可以隐式转换为const引用/指针,但是反过来不行。eg: int a, const int b = 10; ===> my_max(int&, const int&) 编译失败,注意arg2是const int&了。
    ② 数组或函数指针转换:数组可以隐式转换为“指向第1个元素的指针”;参数为“函数的名字” 时,它隐式转换为“函数指针”(传入函数名和函数名的地址都会推导为函数指针)。
    其他隐式转换都不支持,比如:算术转换、派生类对象向上转换、

    (2)苛刻的类型匹配
    参数类型必须完全匹配;如果不能直接匹配,则可以进行“有限的类型转换”;如果还不匹配,推导失败

    (3)参数类型为传值时
    忽略实参的const,volatile等属性,因为传值时,会临时生成一个变量,此变量可读可写。

    (4)可以在函数模板中打印匹配结果
    std::cout<<__PRETTY_FUNCTION__;
    eg: T& my_max(T&, T&) [with T = int]


    4.例子

    int ia = 1, ib = 2;
    double da= 1.2; db= 2.1;
    mymax(ia, ib);    // "函数模板"会根据参数类型生成"模板函数"mymax<int>
    mymax(da, db);    // "函数模板"会根据参数类型生成"模板函数"mymax<double>
    mymax(ia, db);  // 错,没有mymax(int&, double&)
    mymax<double>(ia, db); // 错,没有mymax(int&, double&)
    mymax(static_cast<double>(ia), db); // 错,double& a=static_cast<double>(ia); 本身就是错误代码 (想深入理解,请自行学习“右值”)
    double dc=static_cast<double>(ia); mymax(dc, db); //ok
    mymax(ia, 7);     // 错, int& b = 7; 本身就是错误代码
    const int cb = 5; mymax(ia, cb); // 错, 没有mymax(int&, const int&)

    5.C++中const修饰的变量成为真正的常量,需要在定义时进行初始化。


    6.函数模板重载

    eg:
    char* mymax(char* a, char* b) { //普通函数
        return strcmp(a, b) < 0 ? b : a;
    }
    
    template<typename T>
    T* mymax(T* a, T* b) {
        return (*a < *b) ? b : a;
    }
    
    template<typename T>
    T& mymax(T& a, T& b) {
        return (a < b) ? b : a;
    }

    7.函数模板重载时的选择规则
    (1)先列出候选函数,包括普通函数、参数推导成功的模板函数
    (2)这些候选函数,根据“类型转换”来排序(注意:模板函数只支持有限的类型转换)
    (3)如果某个候选函数的参数跟调用时传入的参数更匹配,则选择此候选函数
    (4)如果这些候选函数的参数匹配度相同
      ①如果只有一个非模板函数,则选择它
      ②如果只有模板函数,则选择“更特化”的模板函数
      ③否则,最后导致“二义性”错误(ambiguous)

    二、例子

    #include <iostream>
    #include <string.h>
    #include <unistd.h>
    
    using namespace std;
    
    /*
    int& max(int& a, int& b)
    {
        return (a < b)? b : a;
    }
    
    double& max(double& a, double& b)
    {
        return (a < b)? b : a;
    }
    
    float& max(float& a, float& b)
    {
        return (a < b)? b : a;
    }
    */
    
    template<typename T>
    const T& mymax(const T& a, const T& b)
    {
        cout<<"1: "<<__PRETTY_FUNCTION__<<endl;
        return (a < b)? b : a;
    }
    
    #if 0
    template<typename T>
    const T& mymax(T& a, T& b)
    {
        cout<<"2: "<<__PRETTY_FUNCTION__<<endl;
        return (a < b)? b : a;
    }
    #endif
    
    template<typename T>
    const T mymax(T * a, T* b)
    {
        cout<<"4: "<<__PRETTY_FUNCTION__<<endl;
        return (*a < *b)? *b : *a;
    }
    
    
    char* mymax(char* a, char* b)
    {
        cout<<"3: "<<__PRETTY_FUNCTION__<<endl;
        return strcmp(a, b) < 0? b : a;
    }
    
    int main(int argc, char **argv)
    {
        int ia = 1;
        int ib = 2;
    
        cout<<mymax(ia, ib)<<endl; //1
    
        int *p1=&ia;
        int *p2=&ib;
    
        cout<<mymax(p1, p2)<<endl; //4
    
        char *str1="hello";
        char *str2="Hellod";
    
        cout<<mymax(str1, str2)<<endl; //3
        
    
        return 0;
    }

    优秀博文:
    理解函数模板参数推导:http://blog.csdn.net/coolmeme/article/details/43986163
    C++标准右值引用介绍:http://blog.cnblogs.com/opangle/archive/2012/11/19/2777131.html

  • 相关阅读:
    洛谷 1.5.1 Number Triangles 数字金字塔
    洛谷 Sorting a Three-Valued Sequence 三值的排序
    洛谷 Transformations 方块转换
    POJ 1401 Factorial
    Java面试那些事
    JVM字节码执行引擎
    一个工作三年左右的Java程序员和大家谈谈从业心得
    浅谈volatile关键字
    Java内存模型
    Integer 错误的加锁
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10632356.html
Copyright © 2020-2023  润新知