【C++】深入模板

2023-11-06

1.反向迭代器的优化

1.1优化目标

原来的模拟实现的反向迭代器需要传递三个模板类型

template<class Iterator, class ref, class ptr >
class Reverse_iterator
{
	typedef Reverse_iterator<Iterator,ref,ptr > self;
    ...
}

而这一部分需要在具体的容器中进行定义,无法做到只有迭代器进行封装。如何解决这个问题?

1.2优化

对迭代器类进行处理

template<class T, class ref, class ptr >
struct list_iterator
{
    typedef ref reference;
	typedef ptr pointer;
    .......
}

对方向迭代器进行处理

template<class Iterator>
class Reverse_iterator
{
public:
	typedef Reverse_iterator<Iterator> self;
    typename Iterator::reference operator*()
	{
		Iterator tmp = _it;

		return *(--tmp);
	}
	typename Iterator::pointer operator->()
	{
		Iterator tmp = _it;
		--tmp;
		//返回的是迭代器内部数据类型的指针
		return &(operator*(this));
	}
}

类模板是虚拟类型,在没有实例化前不能去访问他里面内嵌的定义类型,编译器无法进行处理。

使用typename告诉编译器后面的内容是一个类型,待模板实例化以后,再确认具体的类型

template<class Iterator>
class Reverse_iterator
{
public:
	typedef Reverse_iterator<Iterator> self;
    Iterator::reference operator*()
	{
		Iterator tmp = _it;

		return *(--tmp);
	}
	Iterator::pointer operator->()
	{
		Iterator tmp = _it;
		--tmp;
		//返回的是迭代器内部数据类型的指针
		return &(operator*(this));
	}
}
1.3typename的其他使用方式

比如构建一个list的打印模板函数

template <class T>
void print(list<T>& ls)
{
	list<T>::const_iterator it = ls.begin();
	while (it != ls.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

image-20220717012333201

list属于虚拟类型,因此需要在前面加上typename告诉编译器。

template <class T>
void print(list<T>& ls)
{
	typename list<T>::const_iterator it = ls.begin();
	while (it != ls.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}
1.4适合所有容器的打印函数
template <class container>
void print(container& ls)
{
	typename container::const_iterator it = ls.begin();
	while (it != ls.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

2.非类型模板参数

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

//比如实现一个最大大小自定义的静态数组
//array开辟的空间是在栈上
template<class T,size_t N=100>
class array
{
public:
    T& operator[](size_t pos)
    {
        return a[pos];
    }
    const T& operator[](size_t pos) const
    {
        return a[pos];
    }
    size_t size()
    {
        return _size; 
    }
    bool empty()
    {
        return _size==0;
    }
private:
 	T* a[N];
    size_t _size;
}

注意:

浮点数、类对象和字符串类型都不能作为非类型模板参数;

非类型参数必须在编译期确定结果。

最常用的非类型参数是整形:size_t、int、char

3.函数模板特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理 。

template<class T>
bool Less(T a, T b)
{
	return a < b;
}
void test()
{
	Date d1=Date(2022, 7, 12);
	Date d2=Date(2021, 7, 13);
	cout << Less(d1,d2) << endl;
	Date* p1 = new Date(2011,4,25);
	Date* p2 = new Date(2011, 4, 24);
	cout << Less(p1,p2) << endl;
}

image-20220717015522085

这里d1和d2是调用的Date类型的比较运算符重载。而p1和p2比较的地址。如果想要正确的调用less,就需要对模板特化。

template<class T>
bool Less(T a, T b)
{
	return a < b;
}
//特化
template<>
bool Less<Date*>(Date* a, Date*b)
{
	return *a < *b;
}
void test()
{
	Date d1=Date(2022, 7, 12);
	Date d2=Date(2021, 7, 13);
	cout << Less(d2,d2) << endl;
	Date* p1 = new Date(2011,4,25);
	Date* p2 = new Date(2011, 4, 24);
	cout << Less(p1,p2) << endl;
}

//多个模板参数的特化
template<class T1,class T2>
void print(T1 a,T2 b)
{
	cout << "print(T1,T2)" << endl;
}
template<>
void print<int, char>(int a, char b)
{
	cout << "print(int,char)" << endl;
}

4.类模板特化

4.1全特化

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

template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
template<>
class Data<int, char>
{
public:
	Data() { cout << "Data<int, char>" << endl; }
private:
	int _d1;
	char _d2;
};
void testData()
{
	Data<int, int> d1;
	Data<int, char> d2;
}

image-20220717022607080

4.2偏特化
4.2.1部分模板参数类型特化
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
template<class T1>
class Data<T1, int>
{
public:
	Data() { cout << "Data<T1,int>" << endl; }
	T1 _d1;
	int _d2;
};
void testData()
{
	Data<int, int> d1;
	Data<int, char> d2;
}

image-20220717024521948

4.2参数更进一步的限制
//两个参数偏特化为指针类型
template <class T1, class T2>
class Data <T1*, T2*>
{
public:
	Data() {cout<<"Data<T1*, T2*>" <<endl;}
private:
    T1 _d1;
	T2 _d2;
};
//两个参数偏特化为引用类型
template <class T1, class 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;
};
void test()
{
    Data<int *, int*> d3; // 调用特化的指针版本
    Data<int&, int&> d4(1, 2);//调用特化的引用版本
}

image-20220717025031427

4.3迭代器的萃取

迭代器萃取:针对内置类型的迭代器进行特化;因为内置类型的迭代器就是原生的指针

对于内置类型:

image-20220717025500554

将T*重命名为pointer,T&重命名为reference。这样无论是内置类型指针还是封装好的反向迭代器都可以适配迭代器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】深入模板 的相关文章

  • Qt-Qlist 检查包含自定义类

    有没有办法覆盖加载自定义类的 Qt QList 的比较机制 即在 java 中你只需要重写一个比较方法 我有一个带有我的自定义类模型的 QList QList
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • 如何避免情绪低落?

    我有一个实现状态模式每个状态处理从事件队列获取的事件 根据State因此类有一个纯虚方法void handleEvent const Event 事件继承基础Event类 但每个事件都包含其可以是不同类型的数据 例如 int string
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span

随机推荐

  • IHO s-57(ENC)

    IHO S 57 ENC 目前 IHO S 57支持读访问 S 57驱动模型中 S 57数据支持所有的S 57特征数据 S 57对象被翻译成专题数据 S 57几何对象被自动收集 被翻译成几何特征 s 57 Reader依靠两个支持文件 s5
  • Edge浏览器以图搜图插件Search by Image安装与使用

    1 安装插件 2 以图搜图 右键 gt Search by Image gt Yandex 3 成功搜图 4 如果Yandex打不开 看这个文章 Windows系统无法访问 yandex com 解决方案
  • springboot调整请求头大小_解决Springboot get请求是参数过长的情况

    问题原因 Springboot get请求是参数过长抛出异常 Request header is too large 的问题 错误描述 java lang IllegalArgumentException Request header is
  • python3.8+pytorch 1.7.0+cuda10.2+cuDNN

    本文是在电脑中直接安装cuda10 2的过程 如果是要在anaconda环境中安装的话 可以直接只在虚拟环境中使用命令进行安装 用以下链接中的过程即可 在anaconda虚拟环境中安装pytorch和cuda教程 安装过程中看到的不错的教程
  • CVE-2022-30190复现及原理

    今天各厂商都在发布CVE 2022 30190的安全通告 作为一个与Office有关的RCE漏洞 其原理并不复杂 但利用非常简单无脑甚至不用点击 以后钓鱼肯定要经常用 这里简单复现分析下 环境 Win10 0 16299 32位 Micro
  • OLED透明屏原彩优势和特点解析:开创显示技术新时代

    OLED透明屏 原彩作为一项领先的显示技术 正以其卓越的性能和创新的设计特点引起广泛关注 本文将通过深入探讨OLED透明屏 原彩的优势和特点 应用领域 技术发展以及未来前景等方面内容 并结合具体数据 报告和行业动态 为读者提供专业可信的信息
  • java设置httpheaders_HttpClient 请求添加Header头部信息

    HTTP消息可以包含许多描述消息属性的标头 例如内容长度 内容类型 授权等 HttpClient提供了检索 添加 删除和枚举标头的方法 在下面的教程中 我们将演示如何将自定义HTTP头添加到HttpClient和Http请求方法 Maven
  • 蓬莱小课:统计学中18种数据分析方法汇总

    Part1描述统计 描述统计是通过图表或数学方法 对数据资料进行整理 分析 并对数据的分布状态 数字特征和随机变量之间关系进行估计和描述的方法 描述统计分为集中趋势分析和离中趋势分析和相关分析三大部分 集中趋势分析 集中趋势分析主要靠平均数
  • 【Pytorch】第 5 章 :解决多臂老虎机问题

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 【C++】this指针的理解和__thiscall的调用方式

    我们可以从以下三方面来认识this指针 一 为什么会产生this指针 二 this指针的特点 三 thiscall的调用方式 四 问题 一 为什么会产生this指针 class Box public int volume int heigh
  • es guass 案例

    analyze analyzer standard curl XPOST http 192 168 1 47 9200 searchtube search analyzer ik max word analyzer ik max word
  • 国内常见pip使用镜像源地址

    清华大学镜像源 https pypi tuna tsinghua edu cn simple 阿里云镜像源 http mirrors aliyun com pypi simple 中国科技大学镜像源 https pypi mirrors u
  • vmware 共享文件夹hgfs没有显示

    挂载共享文件夹 当完成共享文件夹之后 会出现在 mnt hgfs目录下 如果没有hgfs文件夹则创建 然后进入虚拟机挂载文件夹 然后执行sudo vmhgfs fuse host mnt hgfs 但是有时候并不显示共享的文件夹 但是如果使
  • c++11之数组array

    c 11数组 定义 注意事项 例子 STL array vector list比较 定义 C 11后 标准库引入了更现代化的数组std array cppreference com是这样介绍的 定义于头文件 template lt clas
  • Windows下如何查看被占用进程及结束进程?

    Windows下如何查看被占用进程及结束进程 查找所有运行的端口命令 netstat ano 查找被占用端口对应的PID netstat aon findstr 2990 查找指定PID的进程 tasklist findstr 1004 结
  • C++学习(十六)有关dump的理解

    1 作为动词 转存的意思 将内容从一个位置转存到另一个位置 2 作为名词 转存文件的意思 某些程序生成的文件 比如操作系统生成的调试日志文件
  • Action 无参数委托详解

    C 委托Action Action
  • opencv实战——机器视觉检测和计数

    引言 在机器视觉中 有时需要对产品进行检测和计数 其难点无非是对于产品的图像分割 由于之前网购的维生素片 有时候忘了今天有没有吃过 就想对瓶子里的药片计数 在学习opencv以后 希望实现对于维生素片分割计数算法 本次实战在基于形态学的基础
  • 跳转关键字

    跳转关键字 break continue break 不能单独存在的 可以用在switch和循环中 表示结束 跳出的意思 代码示例 1 吃1 5号包子 for int i 1 i lt 5 i System out println 在吃第
  • 【C++】深入模板

    文章目录 1 反向迭代器的优化 1 1优化目标 1 2优化 1 3typename的其他使用方式 1 4适合所有容器的打印函数 2 非类型模板参数 3 函数模板特化 4 类模板特化 4 1全特化 4 2偏特化 4 2 1部分模板参数类型特化