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,也…...

2023数学建模国赛C题赛后总结
今天国赛的成绩终于出来了,盼星星盼月亮的。之前面试的时候已经把我给推到国奖评委那里去了,可是好可惜,最终以很微小的劣势错失国二。只拿到了广西区的省一。我心里还是很遗憾的,我真的为此准备了很久,虽然当中也有着…...

hiveSQL语法及练习题整理(mysql)
目录 hiveSQL练习题整理: 第一题 第二题 第三题 第四题 第五题 第六题 第七题 第八题 第九题 第十题 第十一题 第十二题 hivesql常用函数: hiveSQL常用操作语句(mysql) hiveSQL练习题整理: 第一题 我…...

【UE4】UE编辑器乱码问题
环境:UE4.27、vs2019 如何解决 问题原因,UE的编码默认是UTF-8,VS的默认编码是GBK 通过"高级保存选项" 直接修改VS的 .h头文件 的 编码 为 UTF-8 步骤1. 步骤2. 修改编码后,从新编译,然后就可以解决编辑器…...

2 创建svelte项目(应用程序)
官网方式搭建: npm create sveltelatest my-app cd my-app npm install npm run dev 官网中介绍: 如果您使用的是 VS Code,安装 Svelte for VS Code 就可以了,以便语法高亮显示。 然后,一旦您的项目设置好了&#…...

手机怎么打包?三个方法随心选!
有的时候,电脑不在身边,只有随身携带的手机,这个时候又急需把文件打包发送给同事或者同学,如何利用手机操作呢?下面介绍了具体的操作步骤。 一、通过手机文件管理自带压缩功能打包 1、如果是iOS系统,就在手…...

SecureFX如何用Public key 連接sftp
點擊connection 右鍵點開站點的properties 點選SSH2--Authentication---Pulickey 先選擇Putty Key Generator save出來的public key(.pub)文件(Putty Key Generator 保存時可能沒加.pub後綴保存,可自行對public key加上後綴.pub) 同時注意要…...

BUUCTF 隐藏的钥匙 1
BUUCTF:https://buuoj.cn/challenges 题目描述: 路飞一行人千辛万苦来到了伟大航道的终点,找到了传说中的One piece,但是需要钥匙才能打开One Piece大门,钥匙就隐藏在下面的图片中,聪明的你能帮路飞拿到钥匙ÿ…...

idea使用gradle教程 (idea gradle springboot)2024
这里白眉大叔,写一下我工作时候idea怎么使用gradle的实战步骤吧 ----windows 环境----------- 1-本机安装gradle 环境 (1)下载gradle Gradle需要JDK的支持,安装Gradle之前需要提前安装JDK8及以上版本 https://downloads.gra…...

本地部署 lama-cleaner
本地部署 lama-cleaner 什么是 lama-cleanerGithub 地址部署 lama-cleaner启动 lama-cleaner 什么是 lama-cleaner lama-cleaner 是一款由 SOTA AI 模型提供支持的免费开源修复工具。 从照片中删除任何不需要的物体、缺陷、人物,或擦除并替换(由稳定扩…...

供应链云仓系统:实现采购、销售、收银、路线规划一体化,高效协同,再创商业价值!
供应链云仓系统是一款集合采购、销售、收银、路线规划等多项功能的软件系统,旨在帮助企业实现业务流程的全面自动化和协同化。通过该系统,企业可以轻松管理供应链的各个环节,提高运营效率,降低成本,实现商业价值的最大…...