现代C++(Modern C++)基本用法实践:四、模板
概述
C++的模板是泛型编程思想的一种实现。C++是强类型语言,处处强调类型。同样的加法运算,int和float的加法运算需定义两个函数(重载),而使用模板则可以只用一个函数(见下面示例)。
这类似我们面向对象所说的多态(定义加法运算,各个类型有不同的实现),所以是所谓静多态的一种实现方式,不同的是,模板在编译期展开生成int和float两个加法函数,如:
template<class T>
T add(T a, T b)
{
return a + b;
}
int v1 = add<int>(1, 2);
// 不显式声明模板参数类型,编译器会试图推断
float v2 = add(1.5f, 2.5f);
/*
实际上编译器生成了两个函数
int add<int>(int a, int b)
float add<float>(float a, float b)
*/
模板不光支持函数模板,还有类模板等,思想是一样的(详情见下面例子)。
模板还有一些特性机制如:模板特化,SFINAE(substitution failure is not an error 替换而非错误),变长参数模板等,另外模板在元编程中也是十分重要的组成部分,我对元编程没有太多实践,读者有兴趣可以自行搜索。
用法举例
参考测试项目ModernCppTest/modrenc_template.cpp
主要内容:
- 函数模板&Lambda函数模板
- 类模板
- 别名模板
- 变量模板
- 值(枚举)作为模板参数(其实int类型也可以)
- 模板特化
- 变长参数模板
- 模板函数的完美转发
#include "ModernCppTestHeader.h"
namespace n_template{
template <class T>
void template_func(T t)
{
LOG_VAR(t);
}
template <class T>
class Number
{
public:
T v;
Number(T v) : v(v)
{
LOG_VAR(v);
}
};
template <class T>
constexpr T pi = T(3.1415926f);
template <int INTVAL>
void log_template_int_value()
{
LOG_VAR(INTVAL);
}
enum class EAnim : int {
Other = 0,
Cat = 1,
Dog = 2,
};
template<EAnim Ty>
class Anim
{
public:
void Bark() { LOG("默认:动物叫"); }
};
template<>
class Anim<EAnim::Dog>
{
public:
void Bark() { LOG("狗:汪汪!"); }
};
template<>
class Anim<EAnim::Cat>
{
public:
void Bark() { LOG("猫:喵喵!"); }
};
// 注意递归基
void log_values()
{
LOG("展开结束");
}
template<class T, class... ARGS>
void log_values(T value, ARGS... args)
{
LOG(value);
log_values(args...);
}
template<class T>
void func_plus(T&& a)
{
auto v = a;
LOG("func_plus v = " << a);
}
template<class T, class... ARGS>
void func_plus(T&& a, T&& b, ARGS... args)
{
func_plus(a + b, std::forward<ARGS>(args)...);
}
template<class T>
void func_mul(T&& a)
{
auto v = a;
LOG("func_mul v = " << a);
}
template<class T, class... ARGS>
void func_mul(T&& a, T&& b, ARGS... args)
{
func_mul(a + b, std::forward<ARGS>(args)...);
}
template <class... ARGS>
void call_func(const std::string& name, ARGS&&... args)
{
if (name == "plus")
func_plus(std::forward<ARGS>(args)...);
else if (name == "mul")
func_mul(std::forward<ARGS>(args)...);
else
LOG("Unknown function name: " << name);
}
}
template<typename T>
using Num = n_template::Number<T>;
void template_test()
{
LOG_FUNC();
LOG_TAG(" 函数模板 ");
{
n_template::template_func(1);
n_template::template_func(1.25f);
LOG("Lambda 函数模板");
auto f = []<class T> (T t) { LOG_VAR(t); };
f(1);
f(1.25f);
}
LOG_TAG("类模板");
{
n_template::Number(1);
n_template::Number(1.25f);
}
LOG_TAG("别名模板");
{
Num<int>(1);
Num<float>(1.25f);
}
LOG_TAG("变量模板");
{
auto v1 = n_template::pi<int>;
auto v2 = n_template::pi<float>;
LOG_VAR(v1);
LOG_VAR(v2);
n_template::log_template_int_value<10>();
n_template::log_template_int_value<20>();
}
LOG_TAG("枚举变量模板&模板特化");
{
n_template::Anim<n_template::EAnim::Dog>().Bark();
n_template::Anim<n_template::EAnim::Cat>().Bark();
LOG("EAnim::Other 没有特化使用默认模板");
n_template::Anim<n_template::EAnim::Other>().Bark();
}
LOG_TAG("变长参数模板");
{
n_template::log_values("jack", 10, 3.14f);
}
LOG_TAG("变长参数模板的完美转发");
{
n_template::call_func("plus", 1, 2, 3, 4);
n_template::call_func("mul", 2, 3);
}
}
现代C++(Modern C++)基本用法实践:四、模板的更多相关文章
- Linux中sed的用法实践
Linux中sed的用法实践 参考资料:https://www.cnblogs.com/emanlee/archive/2013/09/07/3307642.html http://www.fn139 ...
- WebSocket原理与实践(四)--生成数据帧
WebSocket原理与实践(四)--生成数据帧 从服务器发往客户端的数据也是同样的数据帧,但是从服务器发送到客户端的数据帧不需要掩码的.我们自己需要去生成数据帧,解析数据帧的时候我们需要分片. 消息 ...
- 【实践报告】Linux实践四
Linux内核分析 实践四——ELF文件格式分析 一.概述 1.ELF全称Executable and Linkable Format,可执行连接格式,ELF格式的文件用于存储Linux程序.ELF文 ...
- Linux及安全实践四——ELF文件格式分析
Linux及安全实践四——ELF文件格式分析 一.ELF文件格式概述 1. ELF:是一种对象文件的格式,用于定义不同类型的对象文件中都放了什么东西.以及都以什么样的格式去放这些东西. 二.分析一个E ...
- nodejs 实践:express 最佳实践(四) express-session 解析
nodejs 实践:express 最佳实践(四) express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs ...
- Linux find命令的用法实践
一.find命令简介 Linux下find命令在目录结构中搜索文件,并执行指定的操作.Linux下find命令提供了相当多的查找条件,功能很强大.由于find具有强大的功能,所以它的选项也很多,其中大 ...
- Android最佳性能实践(四)——布局优化技巧
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43376527 在前面几篇文章其中.我们学习了怎样通过合理管理内存,以及高性能编码技 ...
- UWP开发之Mvvmlight实践四:{x:bind}和{Binding}区别详解
{x:bind}是随着UWP被推出而被添加的,可以说是Win10 UWP开发专有扩展.虽然 {x:Bind} 缺少{Binding} 中的一些功能,但它运行时所花费的时间和使用的内存量均比 {Bind ...
- Linux课程实践四:ELF文件格式分析
一.ELF文件格式概述 1. ELF文件 ELF:Executable and Linking Format,是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东 ...
- AI (Adobe Illustrator)详细用法(四)
本节主要是介绍和形状相关的操作. 一.外观面板的使用 熟悉外观面板的使用很重要. 1.新增描边 外观面板可以让我们增加多个描边. 点击“新增描边”,系统自动添加一个描边. 选中文字,新增描边,可以修改 ...
随机推荐
- 【Mybatis】(一)
Mybatis简介 提供持久层框架包括SQL Maps和Data Access Objects(DAO). SQL Maps提供数据库数据和java数据的映射关系,换句话说即是封装JDBC的过程. D ...
- 【Spring5】框架新功能
Spring5框架新功能 整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除. Spring5自带了通用的日志封装:log4j2 已经移除了log4 ...
- Elasticsearch搜索功能的实现(五)-- 实战
实战环境 elastic search 8.5.0 + kibna 8.5.0 + springboot 3.0.2 + spring data elasticsearch 5.0.2 + jdk 1 ...
- Prism Sample 7 Modules Directory
这种方式用扫描目录的方式来增加模块,具备最大的灵活性 仍然在App.xaml.cs中增加了以下代码 protected override IModuleCatalog CreateModuleCata ...
- office办公套件基础教程
正文 1.网页端的应用-office全家桶 这里我选择先聊web端的应用,首先,我们来想象一下,只要你有网络,有浏览器,就能打开一个网页,在网页上进行编辑.处理一些word.报表.ppt等,你不需要复 ...
- 【Azure 存储服务】使用 AppendBlobClient 对象实现对Blob进行追加内容操作
问题描述 在Azure Blob的官方示例中,都是对文件进行上传到Blob操作,没有实现对已创建的Blob进行追加的操作.如果想要实现对一个文件的多次追加操作,每一次写入的时候,只传入新的内容? 问题 ...
- Go windows 环境搭建
下载地址 官网下载地址:https://golang.google.cn/dl/ 1.下载完之后 双击msi进行安装 路径可以不用改, 继续next 安装完之后就需要配置环境变量, 找到环境变量 GO ...
- 2022-11-20:小团生日收到妈妈送的两个一模一样的数列作为礼物! 他很开心的把玩,不过不小心没拿稳将数列摔坏了! 现在他手上的两个数列分别为A和B,长度分别为n和m。 小团很想再次让这两个数列变
2022-11-20:小团生日收到妈妈送的两个一模一样的数列作为礼物! 他很开心的把玩,不过不小心没拿稳将数列摔坏了! 现在他手上的两个数列分别为A和B,长度分别为n和m. 小团很想再次让这两个数列变 ...
- 2022-07-28:以下go语言代码输出什么?A:AA;B:AB;C:BA;D:BB。 package main import ( “fmt“ ) func main() { f
2022-07-28:以下go语言代码输出什么?A:AA:B:AB:C:BA:D:BB. package main import ( "fmt" ) func main() { f ...
- 2021-08-08:自由之路。电子游戏“辐射4”中,任务“通向自由”要求玩家到达名为“Freedom Trail Ring”的金属表盘,并使用表盘拼写特定关键词才能开门。给定一个字符串 ring,表
2021-08-08:自由之路.电子游戏"辐射4"中,任务"通向自由"要求玩家到达名为"Freedom Trail Ring"的金属表盘,并 ...