• 模板进阶:非类型模板参数,特化


    一、非类型模板参数

    非类型模板参数,就是用一个常量作为 类/函数 的模板参数,在 类/函数 中可以被当成常量使用。

    template<class T, size_t N>// N 为一个非类型模板参数
    class Stack
    {
    public:
        Stack()
        {
            _a = new T[N];
        }
    protected:
        T* _a;
    };
    
    int main()
    {
        Stack<int, 10> st;// 初始化方式
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    P.S.

    • 浮点数、类对象、字符串不允许作为非类型模板参数
    • 非类型模板参数必须在编译时就确定结果

    二、模板的特化

    首先给定一个 Date 类,并完善必要的函数及运算符重载,以便后续介绍相关概念。

    	class Date
    	{
    	public:
    		Date(int year, int month, int day)
    			:_year(year)
    			, _month(month)
    			, _day(day)
    		{}
    
    		bool operator<(const Date& d)
    		{
    			if (_year < d._year)
    				return true;
    			else if (_year == d._year && _month < d._month)
    				return true;
    			else if (_year == d._year && _month == d._month && _day < d._day)
    				return true;
    			return false;
    		}
    
    		friend ostream& operator<<(ostream& out, const Date& d);
    
    	protected:
    		int _year;
    		int _month;
    		int _day;
    	};
    
    	ostream& operator<<(ostream& out, const Date& d)
    	{
    		out << d._year << " " << d._month << " " << d._day << endl;
    		return out;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    2.1 函数模板特化
    • 函数模板的特化,必须建立在一个基础的函数模板上
    • template<> 函数名<特化的参数类型> { //... }
    • 必须要和模板函数的基础参数类型完全相同,否则编译器会各种报错
    给出下面的一种情景:比较两个日期的大小关系
    template<class T>
    bool Less(T a, T b)
    {
        return a < b;
    }
    
    int main()
    {
        Date d1(2024, 1, 2);
        Date d2(2024, 3, 12);
        cout << Less(d1, d2) << endl;
        
        Date* p1 = &d1;
        Date* p2 = &d2;
        cout << Less(p1, p2) << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Less(d1, d2) 的比较没有问题,而 Less(p1, p2) 的结果则不尽如人意:

    默认情况下,Less(p1, p2) 是在比较 p1 和 p2 的指针大小关系。如果想要做到通过指针就能完成对日期大小的比较,则需要对 Date* 类型特化,重载 Less 函数

    template<> // 格式
    bool Less<Date*>(Date* a, Date* b) 
    {
        return *a < *b;
    }
    
    // 再次强调:**必须要和模板函数的基础参数类型完全相同**,否则编译器会各种报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    注意:

    一般情况函数模板无法实例化出满足要求的函数,我们通常给出具体实现——更简单、方便。

    bool Less(Date* a, Date* b)
    {
        return *a < *b; // 直接实现,不走函数模板的特化
    }
    
    • 1
    • 2
    • 3
    • 4
    2.2 类模板的特化
    2.2.1 全特化

    全特化:将模板参数列表中所有参数都给明

    template<class T1, class T2>
    class AA
    {
    public:
        AA() { cout << "AA" << endl; }
    };
    
    // 格式 与 函数模板特化格式类似
    template<>
    class AA<int, char> // 将模板参数列表中所有参数都给明
    {
    public:
        AA() { cout << "AA" << endl; }
    };
    
    int main()
    {
        AA<int, int> a1;
        AA<int, char> a2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2.2.2 偏特化

    偏特化有两种方式:

    • 部分特化:将模板参数列表中的一部分参数特化
    template<class T>
    class AA<int, T>
    {
    public:
        AA() { cout << "AA" << endl; }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 对参数进一步限制
    template<class T1, class T2>
    class AA<T1&, T2&> 
    {
    public:
        AA() { cout << "AA" << endl; }
    };
    
    template<class T1, class T2>
    class AA<T1*, T2*> 
    {
    public:
        AA() { cout << "AA" << endl; }
    };
    
    int main()
    {
        AA<int*, char*> a1;
        AA<int&, char&> a2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    2.2.3 Date* 特化仿函数示例
    	template<class T>// 普通版本
    	class ComLess
    	{
    	public:
    		bool operator()(T a, T b)
    		{
    			return a < b;
    		}
    	};
    
    	template<>
    	class ComLess<Date*> // 对于 Date* 类型的特化版本
    	{
    	public:
    		bool operator()(Date* a, Date* b)
    		{
    			return *a < *b;
    		}
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    int main()
    {
        priority_queue<Date*, vector<Date*>, ComLess<Date*>> pq;
        pq.push(new Date(2024, 2, 12));
        pq.push(new Date(2024, 2, 22));
        pq.push(new Date(2024, 2, 2));
        
        while (!pq.empty())
        {
            cout << *pq.top() << endl;
            // pq 的元素是指向Date类的指针
            // 如果想观察Date 的大小关系,需要对 pq.top() 解引用
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    golang基本数据类型
    运动控制器PSO位置同步输出(二):PSO模式详解
    ThinkPHP 接口开发过程
    ES6中数组的扩展
    【linux】倒计时小程序
    Visual Studio Code 配置C、C++ 文件debug调试环境
    Android---OkHttp详解
    【kubernetes篇】使用Harbor仓库管理kubernetes镜像
    wpf devexpress 开始点
    《Flask Web 开发指南 pt.2》
  • 原文地址:https://blog.csdn.net/taduanlangan/article/details/136758545