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

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

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...