C++初阶 —— 模板进阶

c++中的enum类型 C++允许程序员创建自己的数据类型,比如本节要将的枚举类型。枚举数据类型是一种由程序员定义的数据类型,其合法值是与它们关联的一组命名整数常量。 之所以被称为枚举类型,就是因为命名常量是作为数据类型定义的一部分而枚举或列出的,以下是枚举类型声明的示例: enum Roster {Tom, Sharon, Bill, Teresa, John}; 该语句将创建一个名为 Roster 的数据类型。... 阅读详情

目录

一,非类型模板参数

二,模板特化

函数模板特化

类模板特化

三,模板分离编译

分离编译

链接失败原因

解决方法

四,附

模板优点

模板缺点


一,非类型模板参数

模板参数分类

  • 类型形参,模板参数列表中,在class/typename后的名称;
  • 非类型形参,使用一个常量作为类或函数模板的一个参数,可将此参数当成常量使用;
template<class T, size_t N=10> //T为类型参数,N为非类型参数
class array
{
public:
	size_t size()
	{
		return sizeof(_array) / sizeof(T);
	}	
private:
	T _array[N];
};

int main()
{
	array<char>arr;
	std::cout << arr.size() << std::endl;
	return 0;
}

注:

  • 非类型形参,可以是整数、枚举、指向objects/function/members的指针或者引用,也可以是常量表达式;
  • 浮点数、类对象、及字符串是不允许作为非类型模板参数的;
  • 非类型模板参数必须在编译期就能确认结果,不能被修改,也不能作为左值;
//enum color 为传统枚举类型,全局命名空间,会隐式类型转换为整形;
//enum class color C++11引入的新类型,将枚举限定在一个作用域内,且不会隐式转换为整形;
enum class color
{
	red, green, blue
};

void func()
{
	cout << "func" << endl;
}

class Ref
{
public:
	void print() { cout << "class ref" << endl; }
}f;

template<class T, color c, void(*func)(), Ref& r>
class A
{
public:
	void print() 
	{ 
		printf("T _a = %c\n", _a);
		printf("int _b = %d\n", _b);
		printf("int _p = %p\n", _p);
		_r.print();
	}
private:
	T _a = 'a';
	int _b = static_cast<int>(c);
	int* _p = (int*)func;
	Ref _r = r;
};

int main()
{
	A<char, color::blue, func, f> a;
	a.print();
	return 0;
}

二,模板特化

        通常,使用模板可实现与类型无关的代码,但对一些特殊的类型可能会得到错误的结果,此时需对模板进行特化,即在原模板类的基础上,针对特殊类型进行特殊化实现的方式;

template<class T>
bool IsEqual(const T& left, const T& right)
{
	return left == right;
}

int main()
{
    //实参为整数,调用IsEqual没问题
	cout << IsEqual(1, 1) << endl;

    //实参为指针,调用IsEqual实际上是指针的比较
	const char p1[] = "ab";
	const char p2[] = "ab";
	cout << IsEqual(p1, p2) << endl;
	return 0;
}
template<class T>
bool IsEqual(const T& left, const T& right)
{
	return left == right;
}

//优先匹配现成的
bool IsEqual(const char* left, const char* right)
{
	return strcmp(left, right) == 0;
}

int main()
{
	cout << IsEqual(1, 1) << endl;

	const char p1[] = "ab";
	const char p2[] = "ab";
	cout << IsEqual(p1, p2) << endl;
	return 0;
}

函数模板特化

  • 必须先有一个基础的函数模板;
  • 关键字template后面接<>;
  • 函数名后需接<>,其内指定特化类型;
  • 函数形参列表,必须要和模板函数的基础参数类型完全相同;
//模板特化
//const char* const,第一个const修饰指针指向的对象,第二个const修饰指针本身
template<>
bool IsEqual<const char* const >(const char* const& left, const char* const& right)
{
	return strcmp(left, right) == 0;
}

//如函数模板遇到不能处理或处理有误的类型,可直接将该函数给出
bool IsEqual(char* left, char* right)
{
	return strcmp(left, right) == 0;
}

类模板特化

  • 全特化,即将模板参数列表中所有参数都特化;
  • 偏特化或半特化,部分参数特化、或参数更进一步限制;
//类模板
template<class T1, class T2>
class Data
{
public:
	Data(){cout << "Data<T1, T2>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};
//类模板特化,全特化
template<>
class Data<int, double>
{
public:
	Data(){cout << "Data<int, double>" << endl;}
private:
	int _d1;
	double _d2;
};

//类模板偏特化
template<class T1>
class Data<T1, double>
{
public:
	Data(){cout << "Data<T1, double>" << endl;}
private:
	T1 _d1;
	double _d2;
};
//参数偏特化为指针类型
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(){cout << "Data<T1&, T2&>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};

三,模板分离编译

程序在计算机中的执行过程:

分离编译

  • 一个程序或项目由若干个源文件共同实现,每个源文件单独编译生成目标文件,最后将所有目标文件链接生成单一的可执行文件的过程;

模板不可分离编译(即在头文件声明,源文件定义),此时会报链接错误;

//头文件add.h
template<class T>
T add(const T& a, const T& b);

//源文件add.cpp
template<class T>
T add(const T& a, const T& b)
{
	return a + b;
}

//源文件main.cpp
#include "head.h"
#include<iostream>
int main()
{
	std::cout << add(1, 2) << std::endl;;
	return 0;
}

链接失败原因

  • 源文件add.cpp/main.cpp,分别独立编译最后生成add.obj/main.obj,而在main.cpp中并没有add函数的实现,所以main.obj中仅有一条call指令(声明调用add函数,此时无实际调用地址),将add当成外部链处理(即认为此函数实现代码在另一个.obj文件中);
  • 在链接时,指定call指令后调用add的地址,来实现调用;模板函数是不能直接编译成代码,需实例化才可,但add.cpp中,并没有用到模板函数,也就没有实例化(C++标准规定),也就没有add实现地址;

注:在分离编译环境下,源文件都是独立编译的,编译器并不知道其他源文件的存在,对于函数的调用只能靠链接器;在普通函数情况下没有问题,但遇到模板时就会容易导致链接错误,因为模板仅在需要时才会实例化;当编译器遇到模板声明时,不会实例化模板仅常见具有外部链接的符号期待链接时能够得到符号的地址;

解决方法

  • 将声明和定义放在同一个.h(.hpp)文件中;
  • 在模板定义的文件中,显示实例化,此方法不推荐;
//头文件add.h
template<class T>
T add(const T& a, const T& b);

template<class T>
T add(const T& a, const T& b)
{
	return a + b;
}
//源文件add.cpp
template<class T>
T add(const T& a, const T& b)
{
	return a + b;
}

//显示实例化
//缺点是用一个类型就需实例化一个类型
template
int add(const int& a, const int& b);

//或
template<>
int add(const int& a, const int& b)
{
	return a + b;
}

注:模板是按需实例化的,没有实例化编译器不会检测模板内部语法错误,对类模板的成员函数也是按需实例化的,即调用时才实例化;

四,附

模板优点

  • 模板复用了代码,节省了资源;
  • 更快的迭代开发,C++标准模板库STL因此产生;
  • 增加了代码的灵活性;

模板缺点

  • 模板会导致代码膨胀问题,编译会过长;
  • 出现模板编译错误时,错误信息凌乱,不易定位错误;

Visio 2013安装遇阻?手把手教你搞定注册表权限错误1402(附64位系统特殊处理) 本文详细解析了Visio 2013安装过程中常见的注册表权限错误1402问题,特别是在64位系统下的特殊处理方法。通过分步指导如何修改注册表权限、处理Wow6432Node分支以及使用高级工具如subinacl,帮助用户顺利完成安装并避免常见连带问题。 阅读详情

相关推荐

Loupe Browser实战指南:解锁10xGenomics单细胞数据的可视化奥秘

本文提供了Loupe Browser的实战指南,帮助用户无需编程即可探索和可视化10xGenomics单细胞数据。文章详细介绍了从数据导入、界面导航到细胞亚群鉴定、差异基因分析的核心操作流程,并分享了高级技巧与避坑指南,是快速上手这一强大可视化工具的必备参考。

weixin_29313423的博客 206

C++枚举类型,模板类

1、定义枚举类型 //定义枚举类型,其中对应的分别是 0 1 2 3 4。。。 enum spectrum {red, orange, yellow, green, blue}; spectrum band; 枚举类型的赋值只能是定义的成员之一 枚举类型中没有算数运算 band =red; //合法 成员之一 band=20; //不合法,非枚举...

学习自由 2578

执行HDevelop项目

这一节,我们讲述的是如何用HDevEngine加载和执行一个HDevelop项目。代码部分来源于示例程序exec_program(源文件exec_program.cpp),检测塑料零件边界上的毛刺。1.Step 1:初始化首先,我们包含HALCON/C++和HDevEngine头文件以及命名空间。注意到在这个示例程序中,HDevEngine头文件已经包含在my_hdevoperatorimpl中,所

Z's Palace 2994

C++ 非类型模板参数使用和enum小技巧

使用enum类型作为C++ 模板参数

m0_51216781的博客 1443

推荐系统[八]算法实践总结V3:重排在快手短视频推荐系统中的应用and手淘信息流多兴趣多目标重排技术

快手推荐系统包括了传统的召回、粗排、精排、Learning To Rank 的多目标排序、多目标预估等技术环节。而在这些模块之后的技术环节就属于重排序,主要包括手机端和服务端两部分。服务端通过传统服务器部署重排服务,包括序列重排、多源内容混排、多样性模块。端上部分包括端上重排模型和端上重排策略两部分。重排技术是快手十分重要的技术环节,它的发展速度远快于其他排序环节,属于较新的技术范畴。整个序列的价值并非单 item 效果的累计,如何使得序列价值最大化;

丨汀、的博客 1061

电机控制基础,小白入门篇

电机,这个藏在风扇、电动车、机器人里的“动力心脏”,如何精准控制它的转速、方向甚至力量?这篇博客专为完全零基础的小白打造,用“说人话”的方式拆解电机控制的底层逻辑,帮你从“看不懂电路图”到“能调个简单电机”。 电机控制不是“大神专属”,只要掌握“电生磁、磁生力”的底层逻辑,加上动手实践,小白也能快速入门。这篇博客会陪你从“看电机转”到“让电机听话”,把复杂的控制原理变成能上手玩的“小实验”。准备好你的面包板和电机,我们一起开启“电控之旅”吧!

汽车电子软件领域知识分享 5588

【C++ 泛型编程 入门篇】 C++ 模板元编程之枚举内嵌 实战教程

在C++模板元编程中,枚举可以被用作在编译时执行计算的工具。这是因为枚举的值在编译时被确定,而不是在运行时。这使得它们非常适合用于模板元编程,因为模板元编程需要在编译时执行计算和操作。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 1848

Flutter:如何在Android中实现串口通信调试

本文介绍如何通过flutter_libserialport插件在Flutter中实现串口通信调试。

sg_knight的专栏 6097

【C++ 元编程】生成枚举参数包

在我们使用强枚举时,往往需要生成全枚举的参数包,因此参考STL自己实现了一个: enum class MyEnum { ONE, TWO, THREE, SIZE }; template <typename Enum> struct EnumUtil { template <Enum... E> struct EnumSeq { }; template <Enum E, Enum... NextE&gt

ZiFung_Yip的博客 985

基于深度学习的商品标签识别系统:UI界面 + YOLOv8/v7/v6/v5代码 + 训练数据集

基于YOLO系列模型的商品标签识别系统能够有效解决商品信息提取的自动化问题。通过合理的数据集准备、模型训练和UI设计,我们可以实现一个功能强大的商品标签识别系统。希望本文提供的内容能够为大家提供有价值的帮助。

YOLO 474

基于STM32、HAL库的MICRF112YMM-TR 无线收发器驱动程序设计

内部集成了 VCO、PLL、PA、LNA、混频器、滤波器等射频功能单元,极大减少了外部元件数量,降低了设计和布线难度。: 具有多种工作模式(睡眠、待机、接收、发射),待机电流极低,非常适合电池供电的物联网(IoT)设备。是 Microchip 公司生产的一款高性能、低功耗的单片 UHF ASK/FSK 收发器芯片。: 支持 ASK (幅移键控) 和 FSK (频移键控) 调制,适应不同应用需求。// 可以添加其他配置参数,如中心频率、数据速率等。智能家居(安防、遥控、传感)远程钥匙进入系统 (RKE)

corlin6688的博客 415

【CPP】C++模板:初阶到进阶语法与实用编程示例

探索C++模板的深度与广度,《C++模板:初阶到进阶语法与实用编程示例》带您从基础语法起步,逐步深入到高级特性。本博客结合精炼的理论知识和丰富的代码实例,揭示模板编程的精髓,助您提升开发效率,优化代码结构。无论您是初学者还是资深开发者,都能在这里找到提升C++编程技能的宝贵资源。

BinaryWiker的博客 1380

传统(经典)粒子群算法(PSO)解决单目标优化问题

智能算法:粒子群算法(particle swarm optimizer)—PSO %原理:(1)种群初始化–N(种群数)–D(个体数)–x(i)(粒子位置)–v(i)(粒子速度) % (2)计算每个粒子的适应度值–而适应度值需要选择适应度函数 % (3)对于每个粒子,使用它的适应度值fit[i]和个体的极值pbest(i)进行比较,如果fit[i]>pbest(i),则pbest(i)=fit[i] % (4)同理,对每个粒子用它的适应值与全局极值进行比较,如果比它大,则

weixin_51631044的博客 1295

C++初阶-模板进阶

本文深入探讨了C++模板编程的高级特性,主要包括:1. 非类型模板参数的应用与限制,如静态数组大小的控制;2. 模板特化的概念与实现,包括函数模板特化和类模板特化(全特化与偏特化);3. 模板分离编译的问题及解决方法;4. 模板参数中class与typename的使用区别,特别是在嵌套依赖类型和模板模板参数中的不同应用场景。文章通过具体代码示例详细讲解了这些高级模板特性的使用方法和注意事项,为C++进阶编程提供了重要参考。

博客是在C++/Java/Liunx/算法的学习阶段所写的博客,内容可能不是很全面 876

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【C++初阶】模板进阶

1、模板复用了代码,节省资源,更快的迭代开发2、增强了代码的灵活性。

twlw13的博客 1130

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++初阶:模板进阶

泛型编程和模板 STL 简介 STL(standard template libaray)是 C++ 标准库的重要组成部分:标准模板库。STL 不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架。 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。也成为 HP 版本,是所有STL实现版本的始祖。 P. J. 版本 由

yourfriendyo的博客 595

C++初阶之模板进阶

一起努力,一起奔赴大厂。

Infernal_Puppet的博客 1190

C++初阶 模板进阶

本篇博客主要介绍了模板的特化还有模板的编译分离

小萌新的博客 887

【c++初阶】模板进阶

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。【优点】模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生增强了代码的灵活性【缺陷】模板会导致代码膨胀问题,也会导致编译时间变长出现模板编译错误时,错误信息非常凌乱,不易定位错误。

2301_78611726的博客 990

c++初阶--模板进阶

1. 对于一个数组的越界检查,一个数组如果越界读,可以进行,但读出的结果是随机值;如果进行越界写,系统对于一个数组,在数组后面有两位标志位,这两位有一个默认值,当写的是这两位时,会判断是越界并进行报错,但写的若不是这两位,则不会进行报错。// 定义一个模板类型的静态数组public:private:但由于我们使用非类型模板参数定义的静态数组是在类中进行定义的,所以该静态数组有迭代器(指针),无论对于读还是写,只要越界就会进行报错。

2302_79606537的博客 694

C++初阶——模板进阶

【优点】1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。2.增强了代码的灵活性。【缺陷】1. 模板会导致代码膨胀问题,也会导致编译时间变长。2. 出现模板编译错误时,错误信息非常凌乱不易定位错误。

博客 | 复习知识点 + 练习 + 最终的领悟 | 全力以赴 858

C++ ④ 模板初阶-进阶

C++ ④ 模板初阶-进阶

Zjgyytt_sodayo的博客 1145

C++初阶—模板进阶

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链 接起来形成单一的可执行文件的过程称为分离编译模式。【优点】模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生增强了代码的灵活性【缺陷】模板会导致代码膨胀问题,也会导致编译时间变长出现模板编译错误时,错误信息非常凌乱,不易定位错误。

IfYouHave的博客 914

C++初阶 | [十二] 模板进阶

摘要:非类型模板参数,类模板的特化,模板的分离编译,模板总结

fantastic_13_7的博客 760
上一篇: C++初阶 —— stack/queue
下一篇: C++初阶 —— I/O流
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值