c++之说_12|模板

关于模板,至少我们要先了解几个概念

一:函数模板

二:类模板

三:模板特化

四:形参参数包

模板覆盖的东西太多  我目前也不了解太多

函数模板 语法

template<typename 类型名,typename 类型名,typename ...多参包类型名> 
//内部的typename可写多个 有时我们可能会看到 这里会写 class 意思大概是差不多的
 返回值 函数名(){};
如

template<typename arg, typename ...args>
void set(arg s, args... d)
{
	val = s;
	base::set(d...);
};

这里我们可以看到  template<typename arg, typename ...args>

模板形参类型 有 arg  和  args 形参包 

arg  自然就代表可接受一个参数类型,

而args 形参包也叫变参参数包 可接受多个参数

当然也有要求

一:

模板形参必须可推导,显示实例化也属于可推导

二:

有显示实例化当然也有隐式实例化

但隐式实例化有个要求

函数参数中必须可推导模板形参

template<typename arg, typename ...args>
void set(arg s, args... d)
{
	val = s;
};

模板形参在函数参数中直接用到了

可如此调用  这叫隐式实例化
set(10,'g',50,100); //arg = int   args = {char,int,int}

这叫显示实例化
set<int,char,int,int>(10,'g',50,100); //arg = int   args = {char,int,int}

你会说 我们要是在函数参数中没一一使用到 模板形参怎么办?

template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
	Obj c(s,d...);
};

自然就要显示实例化了  注意必须可推导

set<obj_2>(10, 100);
// Obj = obj_2   agr = int  args ={int}

看就显示实例化了没用到的 Obj 模板形参  我们人看上去也是可推导的 

编译器是人写的所以逻辑也是有些符合我们的思维的

函数特化有两种

偏特化(部分特化)

全特化

说实在的我也不太懂  我只能把我懂的部分 说一下

首先我们先看看 函数模板的偏特化 与 全特化

//主模版
template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
	Obj c(s,d...);
};

//特化版本   args* 形参包中 全为 指针类型
template<typename Obj, typename arg, typename ...args>
void set(arg* s, args*... d)
{
	Obj c(d..., s);
}

//特化版本  Ret(*s)(a...)  非成员函数的函数指针
template<typename Obj, typename Ret,typename ...a,typename ...args >
void set(Ret(*s)(a...), args* ... d)
{
	Obj c((*d)..., s());
}

//全特化   
template<>
void set<obj_2,float,float>(float v, float d)
{
	obj_2 c(d, v);
}

//全特化
template<>
void set<obj_2>(float v, float d,char k)
{
	obj_2 c(d, v);
}

这里有个叫主模版的函数模板   用特化就必须得需要主模版  什么叫主模板?

我的理解中是  函数模板 最基本的哪个

 比如上文

template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
    Obj c(s,d...);
};

这个模板可以容纳下面几个特化出来的函数参数的样子 

比如指针类型  非成员函数的函数指针类型  成员函数的函数指针类型 

也就是说它更加全面

你说都更加全面了 我为什么还有特化

这是为了  处理不同的情况嘛   就和函数重载时  处理不同情况一样

比如


int geti()
{
	return 50;
}


int b = 10, b2 = 100;
set<obj_2>(&b,&b2);
/*
调用的特化版本是
template<typename Obj, typename arg, typename ...args>
void set(arg* s, args*... d)
{
	Obj c(d..., s);
}
*/


set<obj_2>(&geti, &b2);
/*
调用的特化版本是
template<typename Obj, typename Ret,typename ...a,typename ...args >
void set(Ret(*s)(a...), args* ... d)
{
	Obj c((*d)..., s());
}

*/

set<obj_1>(0.5f, 5.3f);
/*
调用主模板版本
template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
	Obj c(s,d...);
};

*/

set<obj_2>(0.5f, 5.3f,'p');
/*
调用的特化版本是
template<>
void set<obj_2>(float v, float d,char k)
{
	obj_2 c(d, v);
}


*/

set<obj_2>(0.f);
/*
调用主模版
template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
	Obj c(s,d...);
};

*/

有人可能看到 有些特化怎么 模板形参比主模版还多

template<typename Obj, typename Ret,typename ...a,typename ...args >
void set(Ret(*s)(a...), args* ... d)
{
	Obj c((*d)..., s());
}

这就是模板特化的一部分特性  注意 特化版本的模板形参与主模版的模板形参并无瓜葛 

就算他们是一样的名字 

但是实则是有一定要求的

比如

//主模板
template<typename Obj, typename arg>
void set1(arg c) { Obj c{}; };

//全特化
template<>
void set1<obj_2,float>(float c) { obj_2 bc{}; };

//错误特化版本  
template<>
void set1<obj_2,int,char>(int c) {};
/*
    这里我们注意到了, set1<obj_2,int,char>  有三个模板实参 
    而 我们的主模板只需要 两个模板实参  
    这就是要求:  
    不能大于主模版要求的模板形参数目

*/

//错误特化版本   与上述一样   
template<>
void set1<obj_2>(int c,char b) {};

和函数重载  很类似的规则

有人会问了 那你第一种怎么可写好多个模板实参?

注意主模版哦

template<typename Obj,typename arg, typename ...args>
void set(arg s, args... d)
{
	Obj c(s,d...);
};

一眼上去三个模板形参   但是我们最后是个模板形参包啊

不限个数的啊  超过两个的形参  统统进入形参包

这里可能有少年提出这样的写法

template<typename arg, typename ...args>
void set<obj_2>(arg s, args... d)
{
	obj_2 c(s,d...);
};

看着 嗯.....  我就特化处理  这个obj_2类型的 

不过可惜 这样写法是错误的

注意右边的 编译输出错误

好了函数模板的特化说完了

---------------------------------------------------

现在我们来看看类模板

      

上模板

//主模版
template<typename tp>
struct t1
{
};

//特化版本
template<typename Ret,typename Clss,typename ...Args>
struct t1 <Ret(Clss::*)(Args...)>
{
	using F = Ret(Clss::*)(Args...);
	t1(F fptr):ptr(fptr) {};

	F ptr;
};



int main()
{
	t1<decltype(&obj_2::gets)> b(&obj_2::gets);

	return 0;
}

和函数模板特化差不多

类模板可通过构造函数的参数推断模板形参

template<typename tp>
struct t1
{
	using type = tp;
	t1(tp p) :tpo(p) {};

	tp tpo;
};

template<typename Ret,typename Clss,typename ...Args>
struct t1 <Ret(Clss::*)(Args...)>
{
	using F = Ret(Clss::*)(Args...);
	t1(F fptr):ptr(fptr) {};

	F ptr;
};

int main()
{
	t1<decltype(&obj_2::gets)> b(&obj_2::gets);

	t1 b = t1(&obj_2::gets);//特化版本 struct t1 <Ret(Clss::*)(Args...)>
    // F = int(obj_2::*)(int,int,char);

	t1(obj_2()); // 推断的是主模版  tp = obj_2
	return 0;
}

类模板可以弥补我们之前函数模板的遗憾

template< typename tp>
struct t2<obj_2,tp>
{
	t2(tp p):op(p) {}
	tp op;
	obj_2 d;

};

它可以这样特化

但是又有可惜的事情了


t1 b3 = t1(obj_2()); //ok
auto c =    t2<obj_2,decltype(b3)>(b3); //ok  template< typename tp> struct t2<obj_2,tp>

auto c2 = t2<obj_2>(b3); // error  可惜不可以这样调用  至少我是能看出来 应该可以推导
template<typename obj,typename tp>
struct t2
{
	using type = tp;
	t2(obj* oj,tp p) :ptr(oj), tpo(p) {};
	obj* ptr;
	tp tpo;
};


//main 中

t1 b = t1(&obj_2::gets);
t1 b3 = t1(obj_2());
auto c3 = t2(&b, &b3);//可以

对了  忘记说一件事了

形参包 我们通过特化给它拆开

//主模版
template<typename ...T>
struct Tuple_text {};

//特化
template<>
struct Tuple_text<>
{
	void set() {};
};

//特化
template<typename Ty1, typename ...Ty2>
struct Tuple_text<Ty1, Ty2...> :public Tuple_text<Ty2...> {
	Ty1 val;
	using base = Tuple_text<Ty2...>;
	

	Tuple_text() {}
	
    template<typename arg, typename ...args>
	Tuple_text(arg a, args... d) :val(a), base(d ...) {}
	
	template<typename ...arg>
	void set(arg... args) {};
	template<>
	void set<>() {};

	template<typename arg, typename ...args>
	void set(arg s, args... d)
	{
		val = s;
		base::set(d...);
	};

	base& get()
	{
		return *this;
	}
};

这是今天学习到的  c++元组的类似做法

这里最关键的地方就是

template<>
struct Tuple_text<>
{
	void set() {};
};

template<typename Ty1, typename ...Ty2>
struct Tuple_text<Ty1, Ty2...> :public Tuple_text<Ty2...>
{

Ty1 val;
using base = Tuple_text<Ty2...>;


Tuple_text() {}
template<typename arg, typename ...args>
Tuple_text(arg a, args... d) :val(a), base(d ...) {}

}

没想到吧  我们的构造函数都能模板

这个有点复杂

我们展开看看   C++ Insights (cppinsights.io)  这个网站可以展开模板

#include <cstdio>

//主模板
template<typename ... T>
struct Tuple_text
{
};

//特化
template<>
struct Tuple_text<>
{
  inline void set()
  {
  }
  
};


//以下都为特化  实例化后其实也就是特化
template<>
struct Tuple_text<long> : public Tuple_text<>
{
  long val;
  using base = Tuple_text<>;
  inline Tuple_text();
  
  template<>
  inline Tuple_text<long>(long a)
  : Tuple_text<>()
  , val{a}
  {
  }
  
};


template<>
struct Tuple_text<float, long> : public Tuple_text<long>
{
  float val;
  using base = Tuple_text<long>;
  inline Tuple_text();
  
  template<>
  inline Tuple_text<float, long>(float a, long __d1)
  : Tuple_text<long>(__d1)
  , val{a}
  {
  }
  
};


template<>
struct Tuple_text<char, float, long> : public Tuple_text<float, long>
{
  char val;
  using base = Tuple_text<float, long>;
  inline Tuple_text();

  template<>
  inline Tuple_text<char, float, long>(char a, float __d1, long __d2)
  : Tuple_text<float, long>(__d1, __d2)
  , val{a}
  {
  }
  
  
};


template<>
struct Tuple_text<int, char, float, long> : public Tuple_text<char, float, long>
{
  int val;
  using base = Tuple_text<char, float, long>;
  inline Tuple_text();
  
  template<>
  inline Tuple_text<int, char, float, long>(int a, char __d1, float __d2, long __d3)
  : Tuple_text<char, float, long>(__d1, __d2, __d3)
  , val{a}
  {
  }
  
};



int main()
{
  Tuple_text<int, char, float, long> c = Tuple_text<int, char, float, long>(100, 'o', 6.0F, 500L);
  return 0;
}

注意main 函数里

我们看到这是一系列的继承关系

我们去vs 看看内存布局

我们看到  Tuple_text<int, char, float, long> 类里面有所有的 val 

那我们应该怎么拿到呢?

Tuple_text<int, char, float, long> 的 val 很简单

但是 继承的 父类 Tuple_text<char, float, long> 的 val

怎么拿呢?

我们要是能转换为 父类对象就好了

using base = Tuple_text<Ty2...>;

base& get()
{
	return *this;
}

这样是不是就能拿到父类对象了?

Tuple_text<int, char, float, long>  : Tuple_text<char, float, long> :

Tuple_text<float, long> : Tuple_text<long> : Tuple_text<>

每一级的 base 都是本级继承的父类

c.val   c.get().val  c.get().get().val  c.get().get().get().val

Tuple_text<> 这个是我们自己特化的类

是一个空的 所以继承链到此终结

模板编程是面向编译器的

很强大 但是也很难以解读

模板的玩法不只这些  玩法很多很多 看大家积累了 我也需要积累

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/377855.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

006集——where语句进行属性筛选——arcgis

在arcgis中&#xff0c; dBASE 文件除了 WHERE 语句以外&#xff0c;不支持 其它 SQL 命令。选择窗口如下&#xff1a; 首先&#xff0c;我们了解下什么是where语句。 WHERE语句是SQL语言中使用频率很高的一种语句。它的作用是从数据库表中选择一些特定的记录行来进行操作。WHE…

uniapp小程序端使用计算属性动态绑定style样式踩坑

踩坑点: 使用uniapp编译小程序端动态绑定复杂style使用计算属性方式&#xff0c;return必须返回json字符串格式&#xff0c;不能返回object&#xff0c;否则会不起作用。 代码总览 视图层 逻辑层&#xff08;注意这里是使用的计算属性哈&#xff09; 这里我封装成了一个个性化…

安全名词解析-水坑攻击、鱼叉攻击、钓鲸攻击

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 水坑攻击02 鱼叉攻击03 钓鲸攻击 01 水坑攻击 水坑攻击&#xff08;Watering Hole Attack&#xff09;是一种针对特定目标的网络攻击方式。顾名思义&#xff0c;是在受害者必经之路设置了一个“水坑…

PyTorch 2.2大更新!集成FlashAttention-2,性能提升2倍

【新智元导读】新的一年&#xff0c;PyTorch也迎来了重大更新&#xff0c;PyTorch 2.2集成了FlashAttention-2和AOTInductor等新特性&#xff0c;计算性能翻倍。 新的一年&#xff0c;PyTorch也迎来了重大更新&#xff01; 继去年十月份的PyTorch大会发布了2.1版本之后&#…

Octave实现位置式PID算法

由于Matlab不让用&#xff0c;只能“你不让爷用&#xff0c;爷就用别的”&#xff0c;选择开源的Octave以及scilab进行相关领域的学习。Octave的代码和Matlab几乎是100%相同的&#xff0c;只有一些专用的包的函数&#xff0c;可能有些还没来得及写&#xff0c;或者有些差异。但…

NLP_语言模型的雏形 N-Gram 模型

文章目录 N-Gram 模型1.将给定的文本分割成连续的N个词的组合(N-Gram)2.统计每个N-Gram在文本中出现的次数&#xff0c;也就是词频3.为了得到一个词在给定上下文中出现的概率&#xff0c;我们可以利用条件概率公式计算。具体来讲&#xff0c;就是计算给定前N-1个词时&#xff0…

Redis篇之redis是单线程

一、redis是单线程 Redis是单线程的&#xff0c;但是为什么还那么快&#xff1f;主要原因有下面3点原因&#xff1a; 1. Redis是纯内存操作&#xff0c;执行速度非常快。 2. 采用单线程&#xff0c;避免不必要的上下文切换可竞争条件&#xff0c;多线程还要考虑线程安全问题。 …

硬件大熊原创合集(2024/01更新)

则2024-01月份更新篇章&#xff1a; NFC芯片WS1850的9个典型问题-篇章1 凡夫畏果&#xff0c;菩萨畏因 赶在春节前&#xff0c;做个红包封面&#xff0c;一轮操作下来&#xff0c;发现自己在美工设计这块实在是太欠缺&#xff0c;还好图像处理AI出来了&#xff0c;用Midijourne…

软考 系统分析师系列知识点之信息系统战略规划方法(3)

接前一篇文章&#xff1a;软考 系统分析师系列知识点之信息系统战略规划方法&#xff08;2&#xff09; 所属章节&#xff1a; 第7章. 企业信息化战略与实施 第4节. 信息系统战略规划方法 7.4.1 企业系统规划法 7. 确定管理部门对系统的要求 BSP的出发点是管理部门对系统的要…

WordPress如何实现随机显示一句话经典语录?怎么添加到评论框中?

我们在一些WordPress网站的顶部或侧边栏或评论框中&#xff0c;经常看到会随机显示一句经典语录&#xff0c;他们是怎么实现的呢&#xff1f; 其实&#xff0c;boke112百科前面跟大家分享的『WordPress集成一言&#xff08;Hitokoto&#xff09;API经典语句功能』一文中就提供…

Tomcat之虚拟主机

1.创建存放网页的目录 mkdir -p /web/{a,b} 2.添加jsp文件 vi /web/a/index.jsp <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <html> <head><title>JSP a page</title> </head> …

BUUCTF-Real-[Tomcat]CVE-2017-12615

目录 漏洞描述 一、漏洞编号&#xff1a;CVE-2017-12615 二、漏洞复现 get flag 漏洞描述 CVE-2017-12615&#xff1a;远程代码执行漏洞 影响范围&#xff1a;Apache Tomcat 7.0.0 - 7.0.79 (windows环境) 当 Tomcat 运行在 Windows 操作系统时&#xff0c;且启用了 HTTP P…

力扣面试题 05.06. 整数转换(位运算)

Problem: 面试题 05.06. 整数转换 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.通过将两个数进行异或操作求出两个数中不同的位(不同的位异或后为二进制1); 2.统计异或后不同的位的个数(即异或后二进制为1的个数) 复杂度 时间复杂度: O ( 1 ) O(1) O(1) 空间…

《Git 简易速速上手小册》第9章:Git 工作流程定制(2024 最新版)

文章目录 9.1 选择合适的工作流9.1.1 基础知识讲解9.1.2 重点案例&#xff1a;为中等规模的 Python 项目选择 Feature Branch 工作流9.1.3 拓展案例 1&#xff1a;适应 Gitflow 工作流的大型项目9.1.4 拓展案例 2&#xff1a;使用 Forking 工作流的开源 Python 项目 9.2 定制化…

94.网游逆向分析与插件开发-游戏窗口化助手-地图数据获取的逆向分析与C++代码还原

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;升级经验数据获取的逆向分析 码云地址&#xff08;游戏窗口化助手 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;c4351a5b346d8953a1a8e3ec…

Hgame week1 web

1.Bypass it 不准注册&#xff0c;禁用一下js成功注册登录拿到flag 2.ezHTTP 跟着提示走就行 jwt解析一下 3.点击选课发包时候显示已满 一直发包就会选上 每个都一直发包最后就可以全选课成功 后来得知是后天每隔一段时间会放出一些课&#xff0c;一直发包就能在放课的时候选到…

CDN相关和HTTP代理

CDN相关和HTTP代理 参考&#xff1a; 《透视 HTTP 协议》——chrono 把这两个放在一起是因为容易搞混&#xff0c;我一开始总以为CDN就是HTTP代理&#xff0c;但是看了极客时间里透视HTTP协议的讲解&#xff0c;感觉又不仅于此&#xff0c;于是专门写下来。 先说结论&#xf…

计算机组成原理——计算机系统概述

文章目录 概要计算机硬件的基本组成早期冯诺依曼的结构介绍特点 现代计算机的结构介绍五大部件的归属 五大部件存储器&#xff1a;存储体 MAR、MDR运算器控制器 运行原理 计算机软件系统软件和应用软件三种级别的语言编译程序与解释程序的区别 软件硬件功能程序的等价性指令集体…

LLaMA 模型中的Transformer架构变化

目录 1. 前置层归一化&#xff08;Pre-normalization&#xff09; 2. RMSNorm 归一化函数 3. SwiGLU 激活函数 4. 旋转位置嵌入&#xff08;RoPE&#xff09; 5. 注意力机制优化 6. Group Query Attention 7. 模型规模和训练超参数 8. 分布式模型训练 前置归一化与后置…

音视频色彩:RGB/YUV

目录 1.RGB 1.1介绍 1.2分类 1.2.1RGB16 1)RGB565 2)RGB555 1.2.2RGB24 1.2.3RGB222 2.YUV 2.1介绍 2.2分类 2.2.1 YUV444 2.2.2 YUV 422 2.2.3 YUV 420 2.3存储格式 2.3.1 YUYV 2.3.2 UYVY 2.3.3 YUV 422P 2.3.4 YUV420P/YUV420SP 2.3.5 YU12 和…