• STL与泛型编程(第一周)


    part 1 C++模版简介

    一,模版概观

    1.模板 (Templates)是C++的一种特性,允许函数或类(对象)通过泛型(generic types)的形式表现或运行。

     模板可以使得函数或类在对应不同的型别(types) 的时候正常工作,而无需为 每一个型别都写一份代码。

    2.C++主要有两种类型的模板:

      (1)类模板(Class template): 使用泛型参数的类(classes with generic parameters)

      (2)函数模板(Function template): 使用泛型参数的函数(functions with generic parameters)

    3.模版实例化  

      模板的声明(declaration)其实并未给出一个函数或类的完全定义(definition),只是提供了一个函数或类的语法框架(syntacticalskeleton)。

      实例化是指从模板构建出一个真正的函数或类的过程,比如:

    template <typename T> struct Object { . . . };

    可以用来构建诸如Object<int>, Object<char>, Object<int*>, Object<MyClass*>等等不同型别的具体实例。

      实例化有两种类型:

      (1)显式实例化–在代码中明确指定要针对哪种型别进行实例化。
      (2)隐式实例化–在首次使用时根据具体情况使用一种合适的型别进行实例化。

    二,模版函数

    4.函数模版

     定义:函数模板是参数化的一族函数(a family of functions)。

     通过函数模板, 可以定义一系列函数,这些函数都基于同一套代码,但是可以作用在不同型别的参数上。

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

       也可以使用 class 来代替 typename , 但是不推荐使用。

    5.模版的使用

    int i = 1, j = 2;
    max(i, j);    // 正确
    
    int f = 3.1, g = 4.2
    max(f, g);    //正确
    
    max(i, f);    //错误
                  //compile error:  template parameter 'T' is  ambiguous

    6. 模版实例化

     用具体型别替代模板参数T的过程叫做实例化(instantiation);从而产生了一个模板实例。 

     一旦使用函数模板,这种实例化过程便由编译器自动触发的,不需要额外去请求模板实例化。

     如果实例化一种型别,而该型别内部并不支持函数所使用的操作,那么就会导致一个编译错误。

     例如:std::complex并没有重载“>”,也就是说该型别并不支持使用“>”比较大小,而Max函数使用“>”来判断c1、c2的大小,所以无法通过Max(complex1, complex2)得到预期的结果。

     结论: 模板被编译了两次
      1)没有实例化之前,检查模板代码本身是否有语法错误。
      2)实例化期间, 检查对模板代码的调用是否合法。

    7.参数推导

      模板参数是有传递给模板函数的实参决定的不允许自动型别转换:每个T必须严格匹配!

    Max(1, 2) // OK:两个实参的型别都是 int
    Max(1, 2.0) // ERROR:第一个参数型别是 int,第二个参数型别是 double

      一般有两种处理这种错误的方法:

        1) 用 static_cast或强制转换参数型别以使两者匹配。
        2) 显式指定T的型别。

    Max(static_cast<double>(1), 2.0)
    Max<double>(1, 2.0)

    8.函数模版重载

      (1)重载:函数模板也可以像普通函数一样被重载
      (2)同名:非模板函数可以和同名的模板函数共存
      (3)参数推导:编译器通过函数模板参数推导来决定使用调用哪个重载

    // 普通函数
    inline int const& Max(const int const& a, const int const& b) // 第一个
    
    template <typename T>
    inline T const& Max(const T const& a, const T const& b) // 第二个
    
    template <typename T>
    inline T const& Max(const T const& a, const T const& b, const T const& c) // 第三个

      Max(7, 42, 68): 调用接受三个参数的模板 // 调用 第三个
      Max(7.0, 42.0): 调用 Max<double>(参数推导) // 调用 第二个
      Max('a', 'b'): 调用 Max<char>(参数推导) // 调用 第二个
      Max(7, 42): 调用非模板函数,参数型别为 int // 调用 第一个 其他因素都相同的情况下,重载裁决过程调用非模板函数,而不是从模板产生实例
      Max<>(7, 42): 调用 Max< int>(参数推导) // 调用 第二个 允许空模板参数列表
      Max<double>(7, 42): 调用 Max<double>(无需参数推导) // 调用 第二个
      Max('a', 42.7): 调用非模板函数,参数型别为 int // 调用 第一个 对于型别不同的参数只能调用非模板函数( char 型别 'a' 和 double 型别 42.7 都将转化为 int 型别)

      总结
        对于不同的实参型别,模板函数定义了一族函数
        当传递模板实参的时候,函数模板依据实参的型别进行实例化
        可以显式指定模板的实参型别
        函数模板可以重载
        当重载函数模板时, 将改变限制在:显式指定模板参数
        所有的重载版本的声明必须位于它们被调用的位置之前

    三,类模版

      1.1与函数模版类似,类也可以通过函数参数泛化,从而可以构建出一族不同型别的类实例(对象)。

        1.2 类模版实参可以是某一型别或常量(仅限int或enum)。

      2. 类模版实例

    const std::size_t DefaultStackSize = 1024;
    template<typename T, std::size_t n = DefaultStackSize>
    class Stack
    {
    public:
        void Push(const T const& element);
        int Pop(T& element);
        int Top(T& element) const;
    private:
        std::vector<T> m_Members;
        std::size_t m_nMaxSize = n;
    };

      n是编译时定义的常量,n可以有默认值。

      3.类模板的声明

      除了 Copy constructor 之外,如果在类模版中需要使用到这个类本身,比如 operator= ,那么应该使用其完整的定义(Stack<T>),而不是省略型别 T 。如下面的例子所示: 

    template <typename T, std::size_t n>
    class Stack
    {
    public:
        Stack(Stack<T, n> const&); // copy constructor
        Stack<T>& operator= (Stack<T, n> const&); //assignment operator
    };

     4. 类模板的实现

      要定义一个类模板的成员函数,则要指明其是一个模版函数。

     4.1 例如,Push 函数的定义应当如下:

    template <typename T, std::size_t nMaxSize>
    void Stack<T, nMaxSize>::Push(const T const& element)
    {
        if (m_Members.size() >= m_nMaxSize)
        {
            //error handing ...
            return;
        }
    
        m_Members.push_back(element);
    }

      4.2 Pop 函数:从 Stack 中弹出顶部元素,但是没有 pop 出该元素:

    template <typename T, std::size_t nMaxSize>
    int Stack<T, nMaxSize>::Top(T& element) const
    {
        if (m_Members.empty())
            return 0;
    
        element = m_Members.back();
        return 1;
    }
  • 相关阅读:
    安装VS 2015完成后,VS2012 打开报错
    ASP.NET MVC 项目中 一般处理程序ashx 获取Session
    windows平台 查看 dll 程序集 PublicKeyToken
    MySQL 表与字段编码格式报错
    Linux系统下安装MongoDB 指南
    ASP.NET 访问路径 错误提示 HTTP 错误 404.8 原来路径中包含bin目录被拒绝
    ASP.NET 大文件上传
    将类型(int,string,…)转换为 T 类型
    直接插入排序
    MySQL 优化之索引合并(index_merge)
  • 原文地址:https://www.cnblogs.com/fengyubo/p/4828119.html
Copyright © 2020-2023  润新知