• 模板进阶&&模板分离编译的问题与解决


    🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸
    在这里插入图片描述

    一、模板参数

    模板参数分为类型形参与非类型形参
    类型形参:出现在模板参数中,跟在class或者typename之后的参数类型名称
    非类型形参:就是一个常量作为类模板/函数模板的一个参数,在类模板/函数模板中可将该参数当成常量来使用

    1.非类型模板参数

    template<class T,size_t N=100>//缺省参数
    class Array
    {
    private:
    	T _a[N];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的是:浮点数、类对象以及字符串是不允许作为非类型参数的。也就是说,非类型模板参数只允许是整形家族(char类型也算在整形家族),而且非类型模板参数是在编译阶段就要能确定。

    比如库中的array

    库中的array

    template<class T,size_t N> class array;
    
    • 1

    2.类型模板参数

    这个就简单提一下吧,平时正常用的就是这个

    template<class T>
    class Node
    {
    	//...
    private:
    	T data;
    	Node<T> *_next;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    二、模板参数的特化

    特化就是特殊化
    通常情况下,使用模板可以处理一些类型无关的代码,但对一些类型可能会得到一些错误的结果,需要特殊处理,比如:我想实现一个进行小于比较的函数模板,但是对于某些类型,它的行为不是我想要的,针对某些类型进行特殊化处理

    template<class T>
    bool Greater(T left,T right)
    {
    	return left>right;
    }
    template<>
    bool Greater(Date* left,Date* right)//是一个日期类
    {
    	return *left>*right;//日期类中重载了operator>
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再比如后面学哈希的时候,一些哈希函数处理某些类型也需要用到特化,比如哈希函数处理字符串。

    特化不能单独使用,特化必须是对已有的模板进行特化。
    有特化就用特化,没有编译器就会去按模板推演实例化出新的

    1.全特化

    template <class T1,class T2>
    class Date
    {
      ....  
    };
    template<>
    class Date<int,char>
    {
        ....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.偏特化(半特化)

    template<class T1,class T2>
    class Date
    {
        ....
    }
    template<class T1>
    class Date<T1,int>
    {
        ...
    }
    template<class T1,class T2>
    class Date<T1*,T2*>//这也是偏特化
    {
        ...
    }
    template<class T1,class T2>
    class Date<T1&,T2&>//这也是偏特化
    {
        ....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    三、模板的分离编译的问题

    分离编译是指的,模板的声明放在头文件,定义放在源文件

    1.模板的分离编译书写很麻烦

    比如现在我分离编译了模拟实现的vector

    //定义的时候
    template<class T>
    typename vector<T>::iterator vector<T>::insert(typename vector<T>::iterator pos,const T&x)
    {
    	//...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这是遇到的模板中typename和class的第一个区别,这里是因为vector::成员,它不知道你要去访问静态成员还是iterator这个类型。加上typename就是为了告诉编译器vector::iterator是一个类型,不然的化就有二义性,因为静态成员也是这样访问的

    2.模板的分离编译有声明但找不到定义

    解释:生成目标文件之前,头文件的内容早在预编译阶段就被展开到了源文件当中,但是其他的都能链接的上,唯独模板分离编译的链接不上,原因就是模板分离编译的东西没有被实例化(链接之前,多个源文件并不会交汇,比如说我有vector.hpp vector.cpp和test.cpp,test.cpp和vetcor.cpp包含头文件vector.hpp,预编译阶段,vector.hpp展开到了两个源文件当中。但是在编译阶段,在vector.i中并不会去对模板进行编译,因为没有人告诉他准确的T类型)所以在链接阶段链接的时候,只有声明没有定义,链接的时候去符号表中找,找不到,链接错误,问题就出在编译阶段没有被实例化

    所以提倡模板声明和定义不分离(分离是指的在两个文件当中,因为两个源文件不会交互,模板的准确类型得不到),小函数应该放在类中称为内联,大函数应该在类外定义,因为类里只有声明的话就可以更好的看到整个的框架

    3.模板分离编译的解决办法

    解决办法就是显示实例化,但是显示实例化时把类型写死了,所以非常不推荐

    //在分离编译的地方给给定义
    template
    vector<int>;
    
    template
    vector<double>;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    显示实例化可以有多个

    四、模板总结

    优点

    1.模板服用了代码,节省资源,更快的迭代开发,C++标准模板库因此而产生
    2.增强代码的灵活性,重复的事情交给 编译器做

    缺点

    1.模板会导致代码膨胀问题(inline之所以是建议性关键字的问题也是内联会代码碰撞),也会导致编译时间变长
    2.出现模板编译错误时,错误信息非常凌乱,不易定位错误

    在这里插入图片描述

  • 相关阅读:
    奥克斯变频空调的控温温度波动初步研究
    原创|对接三方服务商回调鉴权的程序代码设计
    2023高教社杯全国大学生数学建模竞赛C题代码解析
    力扣 761. 特殊的二进制序列
    R语言使用xts包表示时间序列数据(time series data)
    科技兴关,荣联与天津海关共建基因组数据库及分析平台
    Unreal Engine 学习笔记 (1)—— 日夜交替
    设计模式:访问者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
    Matplotlib绘制动态图
    分享记账软件 设置账本密码防止收支被他人修改
  • 原文地址:https://blog.csdn.net/zhu_pi_xx/article/details/128008587