首页 > 编程语言 >C++——模板详解(下篇)

C++——模板详解(下篇)

时间:2024-07-05 19:31:54浏览次数:18  
标签:下篇 函数 C++ 参数 template size 模板 特化

一、非类型模板参数

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

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

非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

namespace H
{
    // 定义一个模板类型的静态数组
    template<class T, size_t N = 10>
    class array
    {
    public:
        T& operator[](size_t index){return _array[index];}
        const T& operator[](size_t index)const{return _array[index];}
 
        size_t size()const{return _size;}
        bool empty()const{return 0 == _size;}
 
    private:
        T _array[N];
        size_t _size;
    };
}

注意:

1、浮点数、类对象以及字符串是不允许作为非类型模板参数的

2、非类型的模板参数必须在编译期就能确认结果

二、模板的特化

2.1 概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现一个专门用来进行小于比较的函数模板

template<class T>
bool Less(T left, T right)
{
	return left < right;
}

int main()
{
	cout << Less(1, 2) << endl; // 可以比较且结果正确
	
	Date d1(2001, 01, 01);
	Date d2(2001, 01, 02);
	cout << Less(d1, d2) << endl; // 可以比较且结果正确

	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << Less(p1, p2) << endl; // 可以比较但结果错误

	return 0;
}

可以看到,Less绝多数情况下都可以正常比较,但是在特殊情况下就会得到错误的结果。

此时,就需要对模板进行特化,即:在原模板类的基础上,针对特殊类型所进行的特殊化的实现方式。模板特化中分为函数模板特化类模板特化

2.2 函数模板特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表:必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
// 函数模板 —— 参数匹配
template<class T>
bool Less(T left, T right)
{
	return left < right;
}

// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
	return left < right;
}

int main()
{
	cout << Less(1, 2) << endl; 

	Date d1(2001, 01, 01);
	Date d2(2001, 01, 02);
	cout << Less(d1, d2) << endl; 

	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << Less(p1, p2) << endl; 

	return 0;
}

注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单都是将该函数直接给出。

2.3 类模板特化

2.3.1 全特化

全特化即是将模板参数列表中所有的参数都特殊化。

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

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

void Test()
{
	Date<int, int> d1;
	Date<int, char> d2;
}

2.3.2 偏特化

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

偏特化有以下两种表现方式:

  • 部分特化:将模板参数表中的一部分参数特化
// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:
    Data() 
    {
        cout<<"Data<T1, int>" <<endl;
    }
private:
    T1 _d1;
    int _d2;
};
  • 参数进一步限制。偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本
template <typename T1, typename T2>
class Data<T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }

private:
	T1 _d1;
	T2 _d2;
};

//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data<T1&, T2&>
{
public:
	Data(const T1& d1, const T2& d2)
		: _d1(d1)
		, _d2(d2)
	{
		cout << "Data<T1&, T2&>" << endl;
	}

private:
	const T1& _d1;
	const T2& _d2;
};

三、模板总结

【优点】

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

【缺点】

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

标签:下篇,函数,C++,参数,template,size,模板,特化
From: https://blog.csdn.net/m0_73243771/article/details/140188292

相关文章

  • C++list的模拟实现
    链表节点 template<classT> structListNode { ListNode(constT&data=T()) : _data(data) { } ListNode<T>*_prev=nullptr; ListNode<T>*_next=nullptr; T_data; };因为之后要访问这个类的成员变量函数和结构体,所以在这里将class直接改为struct......
  • Linux 交叉编译(toolchain) ARM aarch64版 libc++.so 库
    前言全局说明libc++源码libc++是LLVM项目提供的一个C++标准库的实现,它是KonaKart等项目的基础。由于libc++是开源>的,因此您可以在其官方仓库中找到源代码。一、说明如果您想要阅读libc++的源代码,可以按照以下步骤进行:访问libc++的官方GitHub仓库:https://github.com/llv......
  • 哈希处理字符串(模板)
    841.字符串哈希-AcWing题库#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl'\n'constintN=1e5+10;intp=131;//13331intP[N],h[N];//P存的是p的k次方,h存字符串前k个数(换化成ascll码)intfind(intl,intr){returnh[r......
  • C++基础知识持续更新,今天来记录结构体的基本知识,包括结构体的定义和使用,结构体数组,结
    C++结构体C++基础知识持续更新,今天来记录结构体的基本知识,包括结构体的定义和使用,结构体数组,结构体指针,结构体嵌套结构体,结构体做函数参数,结构体中的const的使用场景,以及结构体的案例。1.结构体的定义和使用结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。......
  • 二分模板及其原理
    直接上代码#include<bits/stdc++.h>usingnamespacestd;//#defineintlonglong//防止越界//#defintdoublelongdouble//防止越界constintL=0,R=1e9+1;//整数二分边界//constdoubleL=0,R=1e9+1;//实数二分边界constdoubleEPS=1;......
  • C++基础语法篇
    一、语法1.定义变量并赋值:数据类型 变量名=值;2.宏常量定义#define会报错,提示转换:constexprauto数据类型常量名=常量值;3.定义普通(局部)常量:const 数据类型常量名=常量值;4.sizeof关键字,查询占用空间 sizeo......
  • C++ 类型转换注意事项总结
    在C++中,类型转换是编程过程中不可避免的一部分,但不当的类型转换可能会导致程序错误、数据损坏甚至程序崩溃。因此,了解类型转换的注意事项至关重要。以下是C++类型转换时需要注意的几个方面:1.区分隐式类型转换和显式类型转换隐式类型转换:由编译器自动完成,无需程序员干预。......
  • 《C++ Primer》导学系列:第 17 章 - 标准库特殊设施
    17.1tuple类型C++11引入的tuple类型是一个可以包含多个不同类型元素的固定大小容器。tuple类似于pair,但其可以容纳多个元素,不限于两个。这使得tuple非常适合用来返回多个值的函数或者需要存储异构数据的场景。17.1.1定义和初始化tuple定义和初始化tuple非常简单,可以使用st......
  • C++语言相关的常见面试题目(三)
    1.List底层实现原理省流:list底层实现了一个双向循环链表。每个元素(或节点)包含三个部分:数据域(_M_Storage)、前驱指针(_M_prev)、后继指针(_M_next)。数据域:存储实际数据。前驱指针:指向链表中当前节点之前的一个节点。后继指针:指向链表中当前节点之后的一个节点此外,存......
  • C++编程逻辑讲解step by step:多态
    概念 C++面向对象中的多态性是指同一种类型的对象在不同的情况下表现出不同的行为。从代码层面看,实际上“同一种类型”就表明了,这里可以在循环里用相同的代码统一处理不同的功能。这一点很重要。题目界面上,拖动鼠标画矩形或者椭圆。分析先定义出矩形CShpRectangle和椭圆......