C++模板编程——typelist的实现

文章最后给出了汇总的代码,可直接运行

1. typelist是什么

typelist是一种用来操作类型的容器。和我们所熟知的vector、list、deque类似,只不过typelist存储的不是变量,而是类型。

typelist简单来说就是一个类型容器,能够提供一系列的操作。

本文将展示使用元编程实现typelist。

2. 要实现的typelist的接口

在此列举一下即将要编写的typelist的所有接口:

  • typelist:要实现的容器类型。
  • front<typelist>:获取容器中的第一个元素。
  • size<typelist>:获取容器的元素数量。
  • pop_front<typelist, elem>:移出第一个元素。
  • push_front<typelist, elem>:向开头插入一个元素。
  • push_back<typelist, elem>:向结尾插入一个元素。
  • replace_front<typelist, elem>:替换第一个元素。
  • is_empty<typelist>:判断是否为空。
  • find<typelist, index>:查找下标为index的元素。
  • get_maxsize_type<typelist>:容器中尺寸(sizeof)最大的元素。
  • reverse<typelist>:翻转容器中的元素。 
  • filter<typelist, Pre>:根据谓词Pre来过滤typelist中的类型。Pre应该是一个类模板,接受一个类型模板参数,并拥有一个bool类型的静态变量value,value为false时将该类型剔除typelist。

3. 接口实现

3.1 容器

template<typename... Elems>
struct typelist{};

3.2 front<typelist>

template<typename TPLT>// typelist的简写
struct front;

struct front<typelist<FirstElem, OtherElems...>>
{
    using type = FirstElem;
};

3.3 size<typelist>

template<typename TPLT>
struct size;

template<typename... Elems>
struct size<typelist<Elems...>>
{
    static inline const value = sizeof...(Elems);
};

3.4 pop_front<typelist, elem>

template<typename TPLT>
struct pop_front;

template<typename FirstElem, typename... OtherElems>
struct pop_front<typelist<FirstElem, OtherElems...>
{
    using type = typelist<OtherrElems...>;
};

3.5 push_front<typelist, elem>

template<typename TPLT, typename newElem>
struct push_front;

template<typename... Elems, typename newElem>
struct push_front<typelist<Elems...>, newElem>
{
    using type = typelist<newElem, Elems...>;
};

3.6 push_back<typelist, elem>

template<typename TPLT, typename newElem>
struct push_back;

template<typename... Elems, typename newElem>
struct push_back<typelist<Elems...>, newElem>
{
    using type = typelist<Elems..., newElem>;
};

3.7 replace_front<TPLT, elem>

template<typename TPLT, typename Elem>
struct replace_front;

template<typename FirstElem, typename... OtherElems, typename Elem>
struct replace_front<typelist<FirstElem, OtherElems...>, Elem>
{
    using type = typelist<Elem, OtherElems...>;
};

3.8 is_empty<TPLT>

template<typename TPLT>
struct is_empty;

template<typename... Elems>
struct is_empty
{
    static inline const bool value = sizeof...(Elems) == 0;
};

3.9 find<typelist, index>

template<typename TPLT, size_t index>
struct find : find<typename pop_front<TPLT>::type, index - 1>
{
	
};

template<typename TPLT>
struct find<TPLT, 0> :front<TPLT>
{
};

3.10 get_maxsize_type<typelist>

template<typename TPLT>
struct get_maxsize_type
{
private:
	using FirstType = typename front<TPLT>::type;
	using RemainLT = typename pop_front<TPLT>::type;
	using RemainMaxType = typename get_maxsize_type<RemainLT>::type;
public:
	using type = conditional_t < (sizeof(FirstType) > sizeof(RemainMaxType)),
		FirstType, RemainMaxType >;
};

template<typename Elem>
struct get_maxsize_type<typelist<Elem>>
{
	using type = Elem;
};

template<>
struct get_maxsize_type<typelist<>>;

3.11 reverse<typelist>

template<typename TPLT>
struct reverse
{
private:
	using FirstElem = typename front<TPLT>::type;
	using RemainTL = typename pop_front<TPLT>::type;
	using ReversedRemainTL = typename reverse<RemainTL>::type;
public:
	using type = typename push_back<ReversedRemainTL, FirstElem>::type;
};


template<>
struct reverse<typelist<>>
{
	using type = typelist<>;
};

template<typename TPLT, bool = is_empty<TPLT>::value>
struct reverse;

template<typename TPLT>
struct reverse<TPLT, false>
{
private:
	using FirstElem = typename front<TPLT>::type;
	using RemainTL = typename pop_front<TPLT>::type;
	using ReversedRemainTL = typename reverse<RemainTL>::type;
public:
	using type = typename push_back<ReversedRemainTL, FirstElem>::type;
};

template<typename TPLT>
struct reverse<TPLT, true>
{
	using type = typelist<>;
};

3.12 filter<typelist, Pre>

// 根据谓词过滤元素,谓词应该是一个类模板,接受一个类型参数,并且具有静态bool变量,false表示过滤掉该类型
template<typename TPLT, template<typename>typename Pre>
struct filter;

template<typename FirstElem, typename... OtherElems, template<typename>typename Pre>
struct filter<typelist<FirstElem, OtherElems...>, Pre>
{
private:
	using RemainFilteredTL = typename filter<typelist<OtherElems...>, Pre>::type;
public:
	using type = std::conditional_t< Pre<FirstElem>::value,
		typename push_front<RemainFilteredTL, FirstElem>::type,
		RemainFilteredTL >;
};

template<template<typename>typename Pre>
struct filter<typelist<>, Pre>
{
	using type = typelist<>;
};
// 测试使用的类模板,用以剔除某个指定的类型
template<typename InputType, typename FilterType = double>
struct test_filter
{
	static constexpr bool value = !std::is_same_v<InputType, FilterType>;  //如果类型是int,就输出false,int不通过
};

 

4. 完整代码

#include <iostream>
#include <type_traits>
#include "typegetter.hpp"

using namespace std;

/*

*/

namespace myTypeList
{
	template<typename... Elems>
	struct typelist {};

	template<typename TPLT>
	struct front;

	template<typename FirstElem, typename... OtherElems>
	struct front < typelist<FirstElem, OtherElems...>>
	{
		using type = FirstElem;
	};

	template<typename TPLT>
	struct size;

	template<typename... Elems>
	struct size<typelist<Elems...>>
	{
		static const inline size_t value = sizeof...(Elems);
	};

	template<typename TPLT>
	struct is_empty;

	template<typename... Elems>
	struct is_empty<typelist<Elems...>>
	{
		static constexpr bool value = sizeof...(Elems) == 0;
	};


	template<typename TPLT>
	struct pop_front;

	
	template<typename FirstElem, typename... OtherElems>
	struct pop_front< typelist<FirstElem, OtherElems...> >
	{
		using type = typelist<OtherElems...>;
	};

	template<typename TPLT, typename newElem>
	struct push_front;

	template<typename... Types, typename newElem>
	struct push_front<typelist<Types...>, newElem>
	{
		using type = typelist<newElem, Types...>;
	};

	template<typename TPLT, typename newElem>
	struct push_back;

	template<typename... Types, typename newElem>
	struct push_back<typelist<Types...>, newElem>
	{
		using type = typelist<Types..., newElem>;
	};

	template<typename TPLT, typename newElem>
	struct replace_front;

	template<typename FirstElem, typename... OtherElems, typename newElem>
	struct replace_front<typelist<FirstElem, OtherElems...>, newElem>
	{
		using type = typelist<newElem, OtherElems...>;
	};

	

	template<typename TPLT, size_t index>
	struct find : find<typename pop_front<TPLT>::type, index - 1>
	{
		
	};

	/*
		和下面的写法是等价的

	template<typename TPLT, size_t index>
	struct find
	{
		using type = typename find<typename pop_front<TPLT>::type, index - 1>::type;
	};

	*/

	template<typename TPLT>
	struct find<TPLT, 0> :front<TPLT>
	{
	};

	/*
		get_maxsize_type: 获取typelist中尺寸最大的类型
	*/

	template<typename TPLT>
	struct get_maxsize_type
	{
	private:
		using FirstElem = typename front<TPLT>::type;
		using RemainLT = typename pop_front<TPLT>::type;
		using RemainMaxElem = typename get_maxsize_type<RemainLT>::type;
	public:
		using type = conditional_t < (sizeof(FirstElem) > sizeof(RemainMaxElem)),
			FirstElem, RemainMaxElem >;
	};

	template<typename Elem>
	struct get_maxsize_type<typelist<Elem>>
	{
		using type = Elem;
	};

	template<>
	struct get_maxsize_type<typelist<>>;


	/*
		reverse: 翻转typelist
	*/
	/*
	
	// 版本一

	template<typename TPLT>
	struct reverse
	{
	private:
		using FirstElem = typename front<TPLT>::type;
		using RemainTL = typename pop_front<TPLT>::type;
		using ReversedRemainTL = typename reverse<RemainTL>::type;
	public:
		using type = typename push_back<ReversedRemainTL, FirstElem>::type;
	};


	template<>
	struct reverse<typelist<>>
	{
		using type = typelist<>;
	};
	*/

	template<typename TPLT, bool = is_empty<TPLT>::value>
	struct reverse;

	template<typename TPLT>
	struct reverse<TPLT, false>
	{
	private:
		using FirstElem = typename front<TPLT>::type;
		using RemainTL = typename pop_front<TPLT>::type;
		using ReversedRemainTL = typename reverse<RemainTL>::type;
	public:
		using type = typename push_back<ReversedRemainTL, FirstElem>::type;
	};

	template<typename TPLT>
	struct reverse<TPLT, true>
	{
		using type = typelist<>;
	};

	// 根据谓词过滤元素,谓词应该是一个类模板,接受一个类型参数,并且具有静态bool变量,false表示过滤掉该类型
	template<typename TPLT, template<typename>typename Pre>
	struct filter;

	template<typename FirstElem, typename... OtherElems, template<typename>typename Pre>
	struct filter<typelist<FirstElem, OtherElems...>, Pre>
	{
	private:
		using RemainFilteredTL = typename filter<typelist<OtherElems...>, Pre>::type;
	public:
		using type = std::conditional_t< Pre<FirstElem>::value,
			typename push_front<RemainFilteredTL, FirstElem>::type,
			RemainFilteredTL >;
	};

	template<template<typename>typename Pre>
	struct filter<typelist<>, Pre>
	{
		using type = typelist<>;
	};
}

class A {};


// 测试使用的类模板,用以剔除某个指定的类型
template<typename InputType, typename FilterType = double>
struct test_filter
{
	static constexpr bool value = !is_same_v<InputType, FilterType>;  //如果类型是int,就输出false,int不通过
};

int main()
{
	using TPL_1 = myTypeList::typelist<char, short, char, int, double, int, long, A, double>;
	using TPL_2 = myTypeList::typelist<>;

	cout << "----------------------------------" << endl;
	cout << "TPLT_1 为:" << TypeGetter<TPL_1>::name << endl;
	cout << "TPLT_2 为:" << TypeGetter<TPL_2>::name << endl;
	cout << "----------------------------------" << endl;

	cout << "TPL_1 的第一个类型为" << TypeGetter< myTypeList::front<TPL_1>::type >::name << endl;
	//cout << "TPL_2 的第一个类型为" << TypeGetter< myTypeList::front<TPL_2>::type >::name << endl;

	cout << "TPL_1 的size为:" << myTypeList::size<TPL_1>::value << endl;
	cout << "TPL_2 的size为:" << myTypeList::size<TPL_2>::value << endl;

	cout << "TPL_1 的pop_front为:" << TypeGetter< myTypeList::pop_front< TPL_1 >::type >::name << endl;
	//cout << "TPL_2 的pop_front为:" << TypeGetter< myTypeList::pop_front< TPL_2 >::type >::name << endl;

	cout << "TPL_1 push_front bool 为:" << TypeGetter< myTypeList::push_front<TPL_1, bool>::type>::name << endl;
	cout << "TPL_2 push_front bool 为:" << TypeGetter< myTypeList::push_front<TPL_2, bool>::type>::name << endl;

	cout << "TPL_1 push_back bool 为:" << TypeGetter< myTypeList::push_back<TPL_1, bool>::type>::name << endl;
	cout << "TPL_2 push_back bool 为:" << TypeGetter< myTypeList::push_back<TPL_2, bool>::type>::name << endl;

	cout << "TPL_1 replace_front with char 为:" << TypeGetter < myTypeList::replace_front< TPL_1, char >::type>::name << endl;

	cout << "TPL_1 index 2 type 为:" << TypeGetter< myTypeList::find<TPL_1, 2>::type > ::name << endl;

	cout << "TPL_1 max size type 为:" << TypeGetter<myTypeList::get_maxsize_type<TPL_1>::type>::name << endl;

	cout << "TPL_1         为:" << TypeGetter<TPL_1>::name << endl;
	cout << "TPL_1 reverse 为:" << TypeGetter<myTypeList::reverse<TPL_1>::type>::name << endl;

	cout << "TPL_1 经过int_filter过滤为:" << TypeGetter<myTypeList::filter<TPL_1, test_filter>::type>::name << endl;
	cout << "TPL_2 经过int_filter过滤为:" << TypeGetter<myTypeList::filter<TPL_2, test_filter>::type>::name << endl;
	return 0;
}

typegetter.hpp的代码如下所示:

#pragma once

#include <string>
#include "boost/type_index.hpp"


template<typename T>
class TypeGetter
{
public:
	static inline const std::string name = boost::typeindex::type_id_with_cvr<T>().pretty_name();
};

 运行结果如下: 

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

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

相关文章

fastadmin 接口请求提示跨域

问题描述 小程序项目&#xff0c;内嵌h5页面&#xff0c;在h5页面调用后端php接口&#xff0c;提示跨域。网上查找解决方案如下&#xff1a; 1&#xff0c;设置header // 在入口文件index.php直接写入直接写入 header("Access-Control-Allow-Origin:*"); header(&q…

只需三步!5分钟本地部署deep seek——MAC环境

MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步&#xff1a;安装谷歌浏览器插件 第一步:下载Ollama 打开此网址&#xff1a;https://ollama.com/&#xff0c;点击下载即可&#xff0c;如果网络比较慢可使用文末百度网盘链接 注&#xff1a;Ollama是…

idea 错误: 找不到或无法加载主类 @C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448

idea 错误: 找不到或无法加载主类 C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448 该错误往往和左下角爱弹出的如下提示是一个意思 Error running ‘PayV3Test1.testTransferBatchesBatchId’ Error running PayV3Test1.testTransferBatchesBatchId. Command lin…

Excel 笔记

实际问题记录 VBA脚本实现特殊的行转列 已知&#xff1a;位于同一Excel工作簿文件中的两个工作表&#xff1a;Sheet1、Sheet2。 问题&#xff1a;现要将Sheet2中的每一行&#xff0c;按Sheet1中的样子进行转置&#xff1a; Sheet2中每一行的黄色单元格&#xff0c;为列头。…

【故障处理】- ora-39126

【故障处理】- ora-39126 一、概述二、报错原因三、解决方法 一、概述 使用xtts迁移源端12.1.0.2版本&#xff0c;进行全库导入时&#xff08;目标端19c&#xff09;&#xff0c;报错ORA-39126. 二、报错原因 根据mos反馈&#xff0c;是数据库bug导致&#xff0c;该bug会在20.…

C#运动控制——轴IO映射

1、IO映射的作用 该功能允许用户对专用 IO 信号的硬件输入接口进行任意配置&#xff0c;比如轴的急停信号&#xff0c;通过映射以后&#xff0c;可以将所有轴的急停信号映射到某一个IO输入口上&#xff0c;这样&#xff0c;我们只要让一个IO信号有效就可以触发所有轴的急停。 进…

MongoDB 扩缩容实战:涵盖节点配置、服务启动与移除操作

#作者&#xff1a;任少近 文章目录 一、扩容在245节点上配置配置config server&#xff1a;配置mongos启动config server安装工具mongosh添加245新节点到副本集配置分片副本集启动路由并分片 二、缩容Conf server上去掉server4shard上去掉server4mongos上去掉server4 一、扩容…

【NLP】第十一章:隐马尔可夫模型 HMM (Hidden Markov Model)

本来是想讲BERT的&#xff0c;但是BERT的重点是部署应用&#xff0c;而且用BERT跑一些NLP领域的很多任务时&#xff0c;一般做法都是BERT后面再串一个概率模型来约束输出&#xff0c;比如串联一个条件随机场CRF模型。而我们还没讲CRF呢&#xff0c;而且要了解CRF需要首先了解隐…

APP端网络测试与弱网模拟!

当前APP网络环境比较复杂&#xff0c;网络制式有2G、3G、4G网络&#xff0c;还有越来越多的公共Wi-Fi。不同的网络环境和网络制式的差异&#xff0c;都会对用户使用app造成一定影响。另外&#xff0c;当前app使用场景多变&#xff0c;如进地铁、上公交、进电梯等&#xff0c;使…

使用k3s高可用部署rancher

本次部署采用3节点的etcd服务2master节点的k3s使用helm部署的ranchervip(keepalived) 一、安装etcd服务 # 准备 3 个节点部署 etcd cd /hskj/tmp wget https://github.com/etcd-io/etcd/releases/download/v3.3.15/etcd-v3.3.15-linux-amd64.tar.gz tar xzvf etcd-v3.3.15-…

Nginx进阶篇 - nginx多进程架构详解

文章目录 1. nginx的应用特点2. nginx多进程架构2.1 nginx多进程模型2.2 master进程的作用2.3 进程控制2.4 worker进程的作用2.5 worker进程处理请求的过程2.6 nginx处理网络事件 1. nginx的应用特点 Nginx是互联网企业使用最为广泛的轻量级高性能Web服务器&#xff0c;其特点是…

uniapp开发h5部署到服务器

1.发行>网站-PC Web或手机H5&#xff08;仅适用于uniapp&#xff09; 2.填写网站域名 3.编译成功后会生成一个unpackage文件夹找到下面的h5 4.接下来会使用一个工具把h5里面的文件放到服务器上面&#xff08;WinSCP使用其他能部署的工具也行&#xff09; 5.登录 6.登录成功后…

【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)

绪论&#xff1a;冲击蓝桥杯一起加油&#xff01;&#xff01; 每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本章是算法训练的第二章----滑动窗口&#xff0c;它的本质是双指针算法的衍生所以我将…

AWTK-WEB 快速入门(4) - JS Http 应用程序

XMLHttpRequest 改变了 Web 应用程序与服务器交换数据的方式&#xff0c;fetch 是 XMLHttpRequest 继任者&#xff0c;具有更简洁的语法和更好的 Promise 集成。本文介绍一下如何使用 JS 语言开发 AWTK-WEB 应用程序&#xff0c;并用 fetch 访问远程数据。 用 AWTK Designer 新…

html 点击弹出视频弹窗

一、效果: 点击视频按钮后,弹出弹窗 播放视频 二、代码 <div class="index_change_video" data-video-src="</

FPGA实现UltraScale GTH光口视频转USB3.0传输,基于FT601+Aurora 8b/10b编解码架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案本博已有的FPGA驱动USB通信方案 3、工程详细设计方案工程设计原理框图输入Sensor之-->OV5640摄像头动态彩条输入视频之-->ADV…

HCIA项目实践--静态路由的总结和简单配置

七、静态路由 7.1 路由器获取未知网段的路由信息&#xff1a; &#xff08;1&#xff09;静态路由&#xff1a;网络管理员手工配置的路由条目&#xff0c;它不依赖网络拓扑的变化进行自动更新&#xff0c;而是根据管理员预先设定的路径来转发数据包。其优点是配置简单、占用系…

Java中如何高效地合并多个对象的List数据:方法与案例解析!

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云/阿里云/华为云/51CTO&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互…

【网络安全 | 漏洞挖掘】价值3133美元的Google IDOR

未经许可,不得转载。 文章目录 正文正文 目标URL:REDACTED.google.com。 为了深入了解其功能,我查阅了 developer.google.com 上的相关文档,并开始进行测试。 在测试过程中,我发现了一个 XSS 漏洞,但它触发的域名是经过正确沙盒化的 *.googleusercontent.com,这符合 …

sqlilabs--小实验

一、先盲注判断 ?id1 and sleep(2)-- 如果发现页面存在注点&#xff0c;使用时间盲注脚本进行注入 import requestsdef inject_database(url):name for i in range(1, 20): # 假设数据库名称长度不超过20low 48 # 0high 122 # zmiddle (low high) // 2while low &l…