概述

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++)基本用法实践:四、模板的更多相关文章

  1. Linux中sed的用法实践

    Linux中sed的用法实践 参考资料:https://www.cnblogs.com/emanlee/archive/2013/09/07/3307642.html http://www.fn139 ...

  2. WebSocket原理与实践(四)--生成数据帧

    WebSocket原理与实践(四)--生成数据帧 从服务器发往客户端的数据也是同样的数据帧,但是从服务器发送到客户端的数据帧不需要掩码的.我们自己需要去生成数据帧,解析数据帧的时候我们需要分片. 消息 ...

  3. 【实践报告】Linux实践四

    Linux内核分析 实践四——ELF文件格式分析 一.概述 1.ELF全称Executable and Linkable Format,可执行连接格式,ELF格式的文件用于存储Linux程序.ELF文 ...

  4. Linux及安全实践四——ELF文件格式分析

    Linux及安全实践四——ELF文件格式分析 一.ELF文件格式概述 1. ELF:是一种对象文件的格式,用于定义不同类型的对象文件中都放了什么东西.以及都以什么样的格式去放这些东西. 二.分析一个E ...

  5. nodejs 实践:express 最佳实践(四) express-session 解析

    nodejs 实践:express 最佳实践(四) express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs ...

  6. Linux find命令的用法实践

    一.find命令简介 Linux下find命令在目录结构中搜索文件,并执行指定的操作.Linux下find命令提供了相当多的查找条件,功能很强大.由于find具有强大的功能,所以它的选项也很多,其中大 ...

  7. Android最佳性能实践(四)——布局优化技巧

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43376527 在前面几篇文章其中.我们学习了怎样通过合理管理内存,以及高性能编码技 ...

  8. UWP开发之Mvvmlight实践四:{x:bind}和{Binding}区别详解

    {x:bind}是随着UWP被推出而被添加的,可以说是Win10 UWP开发专有扩展.虽然 {x:Bind} 缺少{Binding} 中的一些功能,但它运行时所花费的时间和使用的内存量均比 {Bind ...

  9. Linux课程实践四:ELF文件格式分析

    一.ELF文件格式概述 1. ELF文件 ELF:Executable and Linking Format,是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东 ...

  10. AI (Adobe Illustrator)详细用法(四)

    本节主要是介绍和形状相关的操作. 一.外观面板的使用 熟悉外观面板的使用很重要. 1.新增描边 外观面板可以让我们增加多个描边. 点击“新增描边”,系统自动添加一个描边. 选中文字,新增描边,可以修改 ...

随机推荐

  1. 理解Linux系统: 进程

    Linux内核版本: 2.6.11.12 编写代码: 创建进程 创建进程使用fork系统调用,官方文档对于fork的描述: fork() creates a new process by duplic ...

  2. AspNetCore 成长杂记(一):JWT授权鉴权之生成JWT(其一)

    引子 最近不知怎么的,自从学了WebAPI(为什么是这个,而不是MVC,还不是因为MVC的Razor语法比较难学,生态不如现有的Vue等框架,webapi很好的结合了前端生态)以后,使用别人的组件一帆 ...

  3. pytorch在有限的资源下部署大语言模型(以ChatGLM-6B为例)

    pytorch在有限的资源下部署大语言模型(以ChatGLM-6B为例) Part1知识准备 在PyTorch中加载预训练的模型时,通常的工作流程是这样的: my_model = ModelClass ...

  4. MySQL如何获取binlog的开始时间和结束时间

    MySQL数据库恢复到指定时间点时,我们必须通过MySQL全备+MySQL增量备份(可选)+MySQL的二进制日志(binlog)进行重放来恢复到指定时间点,实际的生产环境中,可能一段时间内生成了多个 ...

  5. Golang每日一库之regex

    本文地址: https://www.cnblogs.com/zichliang/p/17387436.html Golang日库合集:https://www.cnblogs.com/zichliang ...

  6. 集线程池应用、多次HttpWebRequest请求,自动切换账号等等的移动信息查询软件

    具体内容就不说了,只是自己留着未来好找而已 主窗体: using System; using System.Collections.Generic; using System.ComponentMod ...

  7. 2023-03-22:给定一个字符串str, 如果删掉连续一段子串,剩下的字符串拼接起来是回文串, 那么该删除叫做有效的删除。 返回有多少种有效删除。 注意 : 不能全删除,删成空串不允许, 字符串长

    2023-03-22:给定一个字符串str, 如果删掉连续一段子串,剩下的字符串拼接起来是回文串, 那么该删除叫做有效的删除. 返回有多少种有效删除. 注意 : 不能全删除,删成空串不允许, 字符串长 ...

  8. 2023-03-11:给定一个N*M的二维矩阵,只由字符‘O‘、‘X‘、‘S‘、‘E‘组成, ‘O‘表示这个地方是可通行的平地, ‘X‘表示这个地方是不可通行的障碍, ‘S‘表示这个地方有一个士兵,全

    2023-03-11:给定一个N*M的二维矩阵,只由字符'O'.'X'.'S'.'E'组成, 'O'表示这个地方是可通行的平地, 'X'表示这个地方是不可通行的障碍, 'S'表示这个地方有一个士兵,全 ...

  9. 2022-07-21:给定一个字符串str,和一个正数k, 你可以随意的划分str成多个子串, 目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合。 返回有几个回文子串。 来

    2022-07-21:给定一个字符串str,和一个正数k, 你可以随意的划分str成多个子串, 目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合. 返回有几个回文子串 ...

  10. 在 ASP.NET Core Web API 中处理 Patch 请求

    一.概述 PUT 和 PATCH 方法用于更新现有资源. 它们之间的区别是,PUT 会替换整个资源,而 PATCH 仅指定更改. 在 ASP.NET Core Web API 中,由于 C# 是一种静 ...