C++模板元模板实战书籍讲解第一章题目讲解
目录
第一题
C++代码示例
第二题
C++代码示例
第三题
3.1 使用std::integral_constant模板类
3.2 使用std::conditional结合std::is_same判断
总结
第四题
C++代码示例
第五题
C++代码示例
第六题
C++代码示例
第七题
C++代码示例
总结
第一题
对于元函数来说,数值与类型其实并没有特别明显的差异:元函数的输入可以是数值或类型,对应的变换可以在数值与类型之间进行。比如可以构造一个元函数,输入是一个类型,输出是该类型变量所占空间的大小---------这就是一个典型的从类型变换为数值的元函数。尝试构造该函数,并测试是否能行。
C++代码示例
#include <iostream>
#include <type_traits>template <typename T>
struct TypeSize {static constexpr size_t value = sizeof(T);
};int main() {std::cout << TypeSize<int>::value << std::endl; // 输出:4(int 类型在大多数平台上占用4个字节)std::cout << TypeSize<double>::value << std::endl; // 输出:8(double 类型在大多数平台上占用8个字节)std::cout << TypeSize<char>::value << std::endl; // 输出:1(char 类型在大多数平台上占用1个字节)return 0;
}
输出结果:
代码详解:
在上面的代码中,我们定义了一个名为TypeSize
的模板结构体,它有一个静态成员变量value
,其默认值是sizeof(T)
,其中T
是TypeSize
的模板参数类型。通过sizeof
运算符,我们可以在编译时获取类型T
的大小,并将其保存在value
中。
在main
函数中,我们分别测试了int
、double
和char
类型的大小,并使用std::cout
输出结果。可以看到,对于每个类型,我们都成功地获取了其在内存中所占空间的大小。
第二题
作为进一步的扩展,元函数的输入参数甚至可以是类型与数值混合的。尝试构造一个元函数,其输入参数为一个类型以及一个整数。如果该类型所对应对象的大小等与该整数,那么返回true,否则返回false。
C++代码示例
#include <iostream>
#include <type_traits>template <typename T, size_t N>
struct CheckSize {static constexpr bool value = sizeof(T) == N;
};int main() {std::cout << std::boolalpha;std::cout << CheckSize<int, 4>::value << std::endl; // 输出:true(int 类型在大多数平台上占用4个字节)std::cout << CheckSize<double, 8>::value << std::endl; // 输出:true(double 类型在大多数平台上占用8个字节)std::cout << CheckSize<char, 2>::value << std::endl; // 输出:false(char 类型在大多数平台上占用1个字节)return 0;
}
输出结果:
代码详解:
我们使用了一个元函数 CheckSize
,结构体 CheckSize
接受两个模板参数:类型 T
和大小 N
。在元函数中,我们使用 sizeof
运算符计算类型 T
的大小,并将其与整数 N
进行比较。如果相等,则元函数的静态成员变量 value
设置为 true
,否则设置为 false
。
第三题
3.1 使用std::integral_constant
模板类
#include <iostream>
#include <type_traits>template <typename T, size_t N>
struct CheckSize : std::integral_constant<bool, sizeof(T) == N> {};int main() {std::cout << std::boolalpha;std::cout << CheckSize<int, 4>::value << std::endl; // 输出:true(int 类型在大多数平台上占用4个字节)std::cout << CheckSize<double, 8>::value << std::endl; // 输出:true(double 类型在大多数平台上占用8个字节)std::cout << CheckSize<char, 2>::value << std::endl; // 输出:false(char 类型在大多数平台上占用1个字节)return 0;
}
使用std::integral_constant
模板类来实现元函数CheckSize
。CheckSize
结构体继承自std::integral_constant
,并提供两个模板参数:bool
类型表示返回类型,以及sizeof(T) == N
作为值。通过继承自std::integral_constant
,我们可以从CheckSize<T, N>
直接访问value
成员变量。
3.2 使用std::conditional
结合std::is_same
判断
#include <iostream>
#include <type_traits>template<typename T, size_t N>
struct CheckSize {static constexpr bool value = std::is_same_v<sizeof(T), N>;
};int main() {std::cout << std::boolalpha;std::cout << CheckSize<int, 4>::value << std::endl; // 输出:true(int 类型在大多数平台上占用4个字节)std::cout << CheckSize<double, 8>::value << std::endl; // 输出:true(double 类型在大多数平台上占用8个字节)std::cout << CheckSize<char, 2>::value << std::endl; // 输出:false(char 类型在大多数平台上占用1个字节)return 0;
}
使用了std::conditional
结合std::is_same
检查类型大小。std::is_same_v
是一个用于判断两个类型是否相同的模板,sizeof(T)
表示类型 T
的大小,在此和 N
进行比较。如果两者相同,则value
被设置为 true
,否则被设置为 false
。
总结
这些是更特殊或不太常见的元函数表示形式,这些形式可能适用于某些特定的使用场景或要求。
第四题
本章讨论了以类模板作为元函数的输出,尝试构造一个元函数,它接收输入后会返回一个元函数,后者接收输入后会再返回一个元函数------这仅仅是一个联系,不必过于在意其应用场景
C++代码示例
#include <iostream>
#include <functional>template <typename Input>
struct FirstLayer {template <typename Func>struct SecondLayer {template <typename... Args>constexpr auto operator()(Args&&... args) const {return Func{}(std::forward<Args>(args)...);}};template <typename Func>constexpr auto operator()(Func) const {return SecondLayer<Func>{};}
};struct MyFunction {template <typename... Args>constexpr auto operator()(Args&&... args) const {return sizeof...(Args);}
};int main() {FirstLayer<int> first;auto second = first(MyFunction{});std::cout << second(1, 2, 3, 4, 5) << std::endl; // 输出:5(返回传入参数的数量)return 0;
}
输出结果:
代码详解:
示例中,FirstLayer
是一个元函数,它接收一个输入类型 Input
。FirstLayer
结构体中定义了一个内部模板结构体 SecondLayer
,它接收一个元函数类型 Func
。SecondLayer
结构体中定义了一个函数调用运算符 operator()
,它接收任意参数 Args...
,并通过调用 Func
来实现对元函数的调用。
FirstLayer
还定义了一个函数调用运算符 operator()
,它接收一个元函数类型 Func
,并返回一个 SecondLayer<Func>
对象,即返回一个闭包(closure)元函数。
在 main()
函数中,我们先创建一个 FirstLayer<int>
对象 first
。然后,我们通过调用 first(MyFunction{})
来传递一个 MyFunction
元函数对象,得到一个 SecondLayer
对象 second
。最后,我们通过调用 second
来调用传入的 MyFunction
元函数,并传递参数 1, 2, 3, 4, 5
。
运行示例代码后,将输出 5
,表示传入的参数数量为 5。
这个示例就是一个接收输入并返回元函数的元函数的实现。当 FirstLayer
元函数接收一个输入类型后,它返回一个闭包元函数 SecondLayer
。你可以继续调用 SecondLayer
元函数,并传递其他的元函数来实现更多的函数组合和操作。
第五题
使用SFINAE构造一个元函数:输入一个类型T,当T存在子类型type时该元函数返回true,否则返回false。
C++代码示例
#include <iostream>
#include <type_traits>template <typename T>
struct HasType {// 检查 SFINAE 的辅助函数template <typename U>static std::true_type test(typename U::type*);template <typename U>static std::false_type test(...);static constexpr bool value = decltype(test<T>(nullptr))::value;
};// 测试用例
struct A {using type = int;
};struct B {};int main() {std::cout << std::boolalpha;std::cout << HasType<A>::value << std::endl; // 输出:true(A 类型存在名为 type 的子类型)std::cout << HasType<B>::value << std::endl; // 输出:false(B 类型不存在名为 type 的子类型)return 0;
}
输出结果:
代码详解:
示例中,HasType
是一个元函数,用于检查类型 T
是否具有名为 type
的子类型。我们先定义了两个辅助函数 test
,一个接收具有 type
子类型的输入类型 U
(使用 typename U::type*
作为函数参数),另一个使用 ...
表示可变参的占位符。在 HasType
元函数中,test<T>(nullptr)
这一表达式启用了 SFINAE 机制,如果传递的类型具有名为 type
的子类型,则会选择第一个辅助函数进行调用,否则会选择第二个辅助函数。使用 decltype
和 std::true_type
、std::false_type
来从辅助函数的返回类型中提取布尔值。
在测试用例中,我们分别检查了类型 A
和类型 B
。因为类型 A
存在名为 type
的子类型,所以 HasType<A>::value
的结果为 true
。而类型 B
不存在名为 type
的子类型,所以 HasType<B>::value
的结果为 false
。
第六题
使用在本章中学到的循环代码书写方式,编写一个元函数,输入一个类型数组,输出一个无符号整形数组,输出数组中的每个元素表示输入数组中相应类型变量的大小。
C++代码示例
#include <iostream>
#include <utility>
#include <array>template <typename... Types>
struct SizeOfArray;// 基本情况:处理空类型数组
template <>
struct SizeOfArray<> {using type = std::array<std::size_t, 0>;
};// 递归情况:处理非空类型数组
template <typename T, typename... Types>
struct SizeOfArray<T, Types...> {using type = std::array<std::size_t, sizeof...(Types)+1>;
};// 辅助函数,打印无符号整型数组
template <std::size_t N, std::size_t... Sizes>
void printSizes(const std::array<std::size_t, N>& sizes, std::index_sequence<Sizes...>) {((std::cout << sizes[Sizes] << ' '), ...);std::cout << std::endl;
}int main() {using MyTypes = std::tuple<int, double, bool, char>;using Sizes = typename SizeOfArray<int, double, bool, char>::type;Sizes sizes;sizes[0] = sizeof(int);sizes[1] = sizeof(double);sizes[2] = sizeof(bool);sizes[3] = sizeof(char);printSizes(sizes, std::make_index_sequence<sizes.size()>()); // 输出:4 8 1 1return 0;
}
输出结果:
代码详解:
在这段代码中,我们定义了一个 SizeOfArray
结构体,用于计算类型数组的大小。它通过递归方式处理类型数组,当类型数组为空时,返回一个大小为 0 的 std::array
,当类型数组非空时,返回一个大小为 sizeof...(Types)+1
的 std::array
,其中 sizeof...(Types)
是类型数组的元素个数。
在 main
函数中,我们定义了一个类型数组 MyTypes
,其中包含了 int
、double
、bool
和 char
类型。然后,我们使用 SizeOfArray
结构体计算 MyTypes
数组中各个类型的大小,并将它们存储在 Sizes
结构体中。
接下来,我们使用 sizeof
操作符获取每个类型的大小,并将它们存储在 sizes
数组中的相应位置。
最后,我们调用 printSizes
函数,打印 sizes
数组中的每个元素。这里使用了 std::make_index_sequence
来生成一个索引序列,使得我们可以使用折叠表达式在 printSizes
函数中依次访问 sizes
数组中的元素。
第七题
使用分支短路逻辑实现一个元函数,给定一个整数序列,判断其中是否存在值为1的元素。如果存在,就返回true,否则返回false
C++代码示例
#include <iostream>// 终止条件,判断最后一个元素是否等于 1
template <int Last>
bool hasOne() {return Last == 1;
}// 递归情况,判断当前元素是否等于 1,并继续判断后面的元素
template <int First, int Second, int... Rest>
bool hasOne() {return (First == 1) || hasOne<Second, Rest...>();
}int main() {bool result1 = hasOne<1, 2, 3, 4>(); // 序列中存在值为1的元素,返回truebool result2 = hasOne<2, 3, 4, 5>(); // 序列中不存在值为1的元素,返回falsestd::cout << "Result 1: " << std::boolalpha << result1 << std::endl;std::cout << "Result 2: " << std::boolalpha << result2 << std::endl;return 0;
}
输出结果:
代码详解:
第一个版本是终止条件,用于判断最后一个元素是否等于1。在这个版本中,我们只有一个模板参数 Last
,当 Last
等于 1 时,返回 true
。
第二个版本是递归情况,用于判断当前元素是否等于1,并继续判断后面的元素。在这个版本中,我们有三个模板参数,分别代表当前元素 First
、下一个元素 Second
,以及剩余的元素 Rest...
。在递归调用时,我们将 Second
作为新的 First
,并继续判断后面的元素。
通过这段代码,我们可以正确判断整数序列中是否存在值为1的元素。
在 main
函数中,我们使用两个示例来测试 hasOne
元函数。第一个示例传入的序列为 <1, 2, 3, 4>
,其中存在值为1的元素,因此返回 true
。第二个示例传入的序列为 <2, 3, 4, 5>
,其中不存在值为1的元素,因此返回 false
。
总结
后续会开始陆续更新第二章,如果有需要博主讲解其他书也可以私信我!!!
相关文章:

C++模板元模板实战书籍讲解第一章题目讲解
目录 第一题 C代码示例 第二题 C代码示例 第三题 3.1 使用std::integral_constant模板类 3.2 使用std::conditional结合std::is_same判断 总结 第四题 C代码示例 第五题 C代码示例 第六题 C代码示例 第七题 C代码示例 总结 第一题 对于元函数来说,…...
Java在互联网网络安全中的应用(三)
目录 1. 互联网网络安全概述 2. Java的网络安全特性 3. 用Java加固网络应用 4. 安全传输 5. 安全框架和工具 6. 实际应用案例 7. 最佳实践和资源 目标 本次技术分享的目标是介绍Java技术在互联网网络安全中的应用,包括关键概念、最佳实践和实际案例。 1. 互…...
VMLogin如何解决跨境电商多账号管理难题?
做跨境电商的,比如亚马逊、eBay这些卖家。随着团队规模的扩大,或者多店铺运营,那么多个店铺多个账号管理就成为了一个困难。如何解决这个问题呢? 首先来看看很多电商卖家多账号管理会面临的问题 经营者通常需要同时管理多个市场…...

STM32创建工程步骤
以创建led工程为例: 新建一个led文件夹 新建一个以led命名的工程(用keil_uVision5)并添加三个组。 Library文件夹里放置库函数文件。 User: 点亮led灯的程序; 直接给寄存器赋值 调用库函数。 #include "stm…...
软考 系统架构设计师系列知识点之边缘计算(1)
所属章节: 第11章. 未来信息综合技术 第4节. 边缘计算概述 1. 边缘计算概念 在介绍边缘计算之前,有必要先介绍一下章鱼。章鱼就是用“边缘计算”来解决实际问题的。作为无脊椎动物中智商最高的一种动物,章鱼拥有巨量的神经元,但…...
vue:写一个数组box和list数组,在保留box数组中原有对象的同时,将list数组中每一个对象插入到box数组后面
前言:由于源码涉及到后端调用数据和一些无关的功能所以我就专门针对这个功能的代码,这样好方便理解。 1、在data中定义两个数组:box和list,并给它们初始化值 data() {return {box: [/*初始的box数组对象*/],list: [/*初始的list…...

Python教程:随机函数,开始猜英文单词的游戏
开始猜英文单词的游戏… 总计生命次数:3次 -----------游戏开始中…----------- ????请猜一个,4位数的单词:mafr 猜错了,再努力一下 -----------你还有2次生命------------ ma?&…...

Unit2_1:动态规划DP
文章目录 一、介绍二、0-1背包问题问题描述分析伪代码时间复杂度 三、钢条切割问题问题描述分析伪代码过程 四、矩阵链乘法背景性质分析案例伪代码 一、介绍 动态规划类似于分治法,它们都将一个问题划分为更小的子问题 最优子结构:问题的最优解包含子问题的最优解。DP适用的原…...

k8s提交spark应用消费kafka数据写入elasticsearch7
一、k8s集群环境 k8s 1.23版本,三个节点,容器运行时使用docker。 spark版本时3.3.3 k8s部署单节点的zookeeper、kafka、elasticsearch7 二、spark源码 https://download.csdn.net/download/TT1024167802/88509398 命令行提交方式 /opt/module/spark…...

linux傻瓜式安装Java环境及中间件
linux配置Java环境及中间件 1.傻瓜式安装Java1.下载2.追加3.刷新测试 2.傻瓜式安装docker1.docker卸载2.docker安装 3.Docker傻瓜式安装Redis1.傻瓜式安装安装并配置 4.Docker傻瓜式安装RabbitMQ5.Docker傻瓜式安装MySql1.拉取2.配置 6.傻瓜式安装Nacos1.官网下载nacos2.SQL文件…...

javascript中的new原理及实现
在js中,我们通过new运算符来创建一个对象,它是一个高频的操作。我们一般只是去用它,而很少关注它是如何实现的,它的工作机制是什么。 1 简介 本文介绍new的功能,用法,补充介绍了不加new也同样创建对象的方…...

R语言 PPT 预习+复习
什么狗吧发明的结业考,站出来和我对线 第一章 绪论 吊码没有,就算考R语言特点我也不背,问就是叫么这没用。 第二章 R语言入门 x<-1:20 赋值语句 x 1到20在x上添加均值为0、标准差为2的正态分布噪声 y <- x rnorm (20, 0, 2) 这…...
轻松实现固定资产智能管理的工具来了
易点易动资产管理系统是一款旨在轻松实现智能资产管理的工具。固定资产管理对于企业的日常经营和可持续发展至关重要。然而,固定资产具有设备价值高、使用周期长、使用地点分散、使用环境恶劣、流动性强、安全管理难度大等特点,传统的管理方式往往无法高…...
软考高级系统架构设计师系列之:微服务
软考高级系统架构设计师系列之:微服务 一、微服务二、微服务的优势三、微服务挑战四、微服务与SOA的对比一、微服务 微服务架构建议将大型复杂的单体架构应用划分为一组微小的服务,每个微服务根据其负责的具体业务职责提炼为单一的业务能力。每个服务可以很容易地部署并发布…...

vue + axios + mock
参考来源:Vue mock.js模拟数据实现首页导航与左侧菜单功能_vue.js_AB教程网 记录步骤:在参考资料来源添加axios步骤 1、安装mock依赖 npm install mock -D //只在开发环境使用 下载完成后,项目文件package.json中的devDependencies就会加…...

Mongoose 开源库--json 使用笔记
一、 json相关API mongoose 开源库可以使用json进行数据处理。 ①创建json字符串 // A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi")) #define MG_ESC(str) mg_print_esc, 0, (str) char *mg_mprintf(const char *fmt, ...)…...
linux中复制文件如何排除一个目录
误区: 首先使用cp命令的 --exclude参数实不可取的,会造成以下的报错,因为cp命令中压根就没有--exclude这个参数的配置 cp: unrecognized option --exclude‘****’ 问题解决: 我们可以使用rsync工具来完成目录排除的功能&#x…...

时空智友企业信息管理系统任意文件读取漏洞复现
简介 时空智友企业信息管理系统是一个用于企业流程管理和控制的软件系统。它旨在帮助企业实现流程的规范化、自动化和优化,从而提高工作效率、降低成本并提升管理水平。 时空智友企业信息管理系统存在任意文件读取漏洞,攻击者可以在未授权的情况下读取…...

YOLOv8优化:block系列篇 | Neck系列篇 |可重参化EfficientRepBiPAN优化Neck
🚀🚀🚀本文改进: 可重参化EfficientRepBiPAN优化Neck 如何在YOLOv8下使用:1)结合neck; 🚀🚀🚀EfficientRepBiPAN在各个领域都有ying 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.原理…...

零代码编程:用ChatGPT批量提取flash动画swf文件中的mp3
文件夹:C:\迅雷下载\有声绘本_flash[淘宝-珍奥下载]\有声绘本 flash,里面有多个flash文件,怎么转换成mp3文件呢? 可以使用swfextract工具从Flash动画中提取音频,下载地址是http://www.swftools.org/download.html,也…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...