【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译)

【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译),第1张

dzc6;个人主页:企鹅不叫的博客

​ 🌈专栏

  • C语言初阶和进阶
  • C项目
  • Leetcode刷题
  • 初阶数据结构与算法
  • C++初阶和进阶
  • 《深入理解计算机 *** 作系统》
  • 《高质量C/C++编程》
  • Linux

⭐️ 博主码云gitee链接:代码仓库地址

⚡若有帮助可以【关注+点赞+收藏】,大家一起进步!

💙系列文章💙

【初阶与进阶C++详解】第一篇:C++入门知识必备

【初阶与进阶C++详解】第二篇:C&&C++互相调用(创建静态库)并保护加密源文件

【初阶与进阶C++详解】第三篇:类和对象上(类和this指针)

【初阶与进阶C++详解】第四篇:类和对象中(类的六个默认成员函数)

【初阶与进阶C++详解】第五篇:类和对象下(构造+static+友元+内部类

【初阶与进阶C++详解】第六篇:C&C++内存管理(动态内存分布+内存管理+new&delete)

【初阶与进阶C++详解】第七篇:模板初阶(泛型编程+函数模板+类模板+模板特化+模板分离编译)

【初阶与进阶C++详解】第八篇:string类(标准库string类+string类模拟实现)

【初阶与进阶C++详解】第九篇:vector

【初阶与进阶C++详解】第十篇:list

【初阶与进阶C++详解】第十一篇:stack+queue+priority_queue+deque


文章目录
  • 💙系列文章💙
  • 💎一、非类型模板参数
  • 💎二、模板的特化
    • 🏆1.函数模板的特化
    • 🏆2.类模板的特化
      • 2.1全特化
      • 2.2偏特化
  • 💎三、模板分离编译
    • 🏆1.实例
    • 🏆2.原因
    • 🏆3.解决方法
  • 💎四、模板优缺点


💎一、非类型模板参数

模板参数分类类型形参与非类型形参。

  • 类型模板形参:出现在模板参数列表中,跟在class或者typename后面的参数类型名称。

  • 非类型模板形参:用一个常量(浮点数,字符串,类对象不允许作为非类型模板参数)(可以是 int short char long longlong)作为模板的一个参数,必须是整形家族中的类型参数。

  • template<class T =int, size_t N = 10>
    class array
    {
        private:
        T _array[N];
        size_t _size;
    }
    
    
💎二、模板的特化

模板特化:在原模板类的基础上,针对特殊类型所进行的特殊化的实现。分为函数模板特化 和类模板特化。

🏆1.函数模板的特化
  1. 必须先有一个基础的函数模板

  2. 关键字template后面接一对空的尖括号<>

  3. 函数名后跟一对尖括号<>,里面指定需要的特化的类型

  4. 函数形参列表:必须和函数模板的基础参数类型完全一致

    // 模板
    template<class T>
    bool IsEqual(T& left, T& right)
    {
    	return left == right;
    }
    
     // 特化
    template<>
    bool IsEqual<const char* const>(const char* const& left, const char* const& right)
    {
    	return strcmp(left, right) == 0;
    }
    
    
🏆2.类模板的特化 2.1全特化

对类模板参数列表的类型全部都确定

template <class T1, class T2>
class Date
{
public:
	Date()
	{
		cout << "Date" << endl;
	}
private:
	T1 _d1;
	T2 _d2;
};

// 全特化
template<>
class Date<int, double>
{
public:
	Date()
	{
		cout << "Date" << endl;
	}
private:
	int _d1;
	double _d2;
};

2.2偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本

偏特化有两种表现方式,一种是部分参数特化,一种是参数修饰特化

部分特化,模板参数类表中一部分参数特化

//第二个参数特化
template<class T1>
class test<T1, double>
{
public:
	test()
	{
		cout << "test" << endl;
	}

private:
	T1 _x;
	double _y;
};
int main()
{
	test<double, double> t1;
	test<int, double> t2;
}

参数更进一步限制,偏特化不指是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本

//如下有T1*和T2*,是模板的类型转为指针类型和引用类型
/template<class T1, class T2>
class test<T1*, T2*>
{
public:
	test()
	{
		cout << "test" << endl;
	}

private:
	T1* _x;
	T2* _y;
};

int main()
{
	test<int*, double*> t;
}

💎三、模板分离编译 🏆1.实例

**分离编译:**C++的编译器却不支持模板的分离编译,一旦进行分离编译,就会出现链接错误,下面代码就会报错。详情看这里传送门

// a.h
#pragma once


// 普通函数
void Swap(int& a, int& b);
// 函数模板
template<class T>
T Add(const T& a, const T& b);

// a.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "a.h"

// 普通函数
void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
// 函数模板
template<class T>
T Add(const T& a, const T& b)
{
	return a + b;
}

// test.cpp
#include "a.h"

int main()
{
	int a = 3;
	int b = 4;

	Swap(a, b);
	cout << "a = " << a << " b = " << b << endl;
	cout << Add(a, b) << endl;
	
	return 0;
}

🏆2.原因

1.模板在.cpp中定义了,由于不知道T的类型,所以没有对模板进行实例化。
2.a.h 和 a.cpp 都没有对模板进行实例化,因为不知道T的类型。
3.因为没有对模板进行实例化,所以没有函数参数,也就没有函数地址,所以在链接时,test.cpp中的调用Add函数时,没有函数地址,call调用不到Add函数,所以报错。

🏆3.解决方法
  1. 暴力:将声明和定义统一放在一个.h或.hpp的文件中
  2. 模板定义位置显示实例化(不推荐,这样就失去了泛型的特点)
💎四、模板优缺点

【优点】

​ 1.模板复用了代码,节省资源,更快的迭代开发

​ 2.增强了代码的灵活性

【缺点】

​ 1.导致编译时间变长

​ 2.出现模板编译错误时,错误信息非常凌乱,不易定位错误


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/2991545.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-23
下一篇 2022-09-23

发表评论

登录后才能评论

评论列表(0条)

保存