C++ 编程技巧之StrongType(1)
最近看到一个NamedType的开源库,被里面的Strong Type这个概念和里面的模版实现给秀了一脸,特此总结学习一下
GitHub - joboccara/NamedType: Implementation of strong types in C++
C++本身是一种强类型语言,类型包括int、double等这些build in类型 以及class类型,强类型的意思是所有变量的类型在编译阶段应该都是确定的。上面提到的Strong Type并不是这个意思,在C++中,Strong Type(强类型)是一种编程技巧,是对C++的类型进行加强的意思。
它用于定义一种类型安全的机制,使得编译器能够区分语义相似但实际意义不同的类型,从而避免因类型混淆导致的潜在错误。这种技术常见于处理需要区分类似数据的场景,比如标识符、单位、或封装基本数据类型以增强可读性和安全性。Strong Type在某种程度上和C++的自定义字面量有点相似,本文也对他们进行一些对比。
强类型的基本思想
强类型通常是通过封装一个原始类型(如 int
, double
等)实现的,我们可以先看如下示例来感受一下用法
通过简单封装赋予语义
struct Meters {
double value;
};struct Seconds {
double value;
};Meters operator+(Meters lhs, Meters rhs) {return Meters{lhs.value + rhs.value};
}// 用法
Meters distance1{5.0};
Meters distance2{10.0};
Meters total = distance1 + distance2; // OK
// Seconds time = distance1; // 编译错误,类型不兼容
通过模板实现通用强类型
template <typename Tag, typename T>
class StrongType {
public:
explicit StrongType(T value) : value_(value) {}
T get() const { return value_; }private:
T value_;
};// 标识语义的标签
struct UserIdTag {};
struct ProductIdTag {};using UserId = StrongType<UserIdTag, int>;
using ProductId = StrongType<ProductIdTag, int>;UserId uid(42);
ProductId pid(101);// pid = uid; // 编译错误,类型不兼容
强类型与操作符重载
如果需要增强强类型的可用性,可以为其定义操作符:
template <typename Tag, typename T>
class StrongType {
public:
explicit StrongType(T value) : value_(value) {}
T get() const { return value_; }// 支持操作符重载
StrongType operator+(const StrongType& other) const {return StrongType(value_ + other.value_);
}private:
T value_;
};struct DistanceTag {};
using Distance = StrongType<DistanceTag, double>;// 用法
Distance d1(5.0), d2(10.0);
Distance total = d1 + d2; // OK
应用场景
- 标识符区分: 避免混淆例如用户 ID 和产品 ID 等数据。
- 物理量单位: 避免直接使用
double
等基础类型混淆不同单位的数值(如米和秒)。 - 类型安全接口: 增强类型安全,避免误用相似类型的数据。
- 业务逻辑抽象: 为关键业务对象创建显式的类型,增强代码可读性和可维护性。
Strong Type 和 C++字面量
上面Strong Type的思想其实和C++字面量有异曲同工之妙,我们不妨也来总结一下C+++自定义字面量的知识。
用户自定义字面量是 C++ 提供的扩展功能,通过为特定的字面量(如整型、浮点型、字符串等)自定义行为,可以实现特定语义,例如单位转换、数据封装等。自定义字面量通常使用 operator""
实现。
基本语法
用户自定义字面量是通过重载 operator""
实现的,后面可以接字面量标识符。根据传入的参数类型,用户自定义字面量分为以下几种形式:
参数类型 | 示例 | 常用场景 |
|
| 处理字符串类型 |
|
| 处理整型字面量 |
|
| 处理浮点型字面量 |
|
| 处理字符字面量 |
|
| 处理字符串并获得长度 |
自定义字面量实现
以下是针对不同类型的自定义字面量的实现方式:
整型字面量
#include <iostream>// 自定义字面量,用于单位转换
constexpr unsigned long long operator"" _kg(unsigned long long value) {return value * 1000; // 转换为克
}int main() {auto weight = 5_kg; // 表示 5 公斤std::cout << "Weight in grams: " << weight << " g\n"; // 输出 5000 greturn 0;
}
浮点型字面量
#include <iostream>// 自定义字面量,用于单位转换
constexpr long double operator"" _m(long double value) {return value * 100; // 转换为厘米
}int main() {auto length = 2.5_m; // 表示 2.5 米std::cout << "Length in cm: " << length << " cm\n"; // 输出 250 cmreturn 0;
}
字符串字面量
#include <iostream>
#include <string>// 自定义字面量,处理字符串
std::string operator"" _hello(const char* str, size_t) {return std::string("Hello, ") + str;
}int main() {auto greeting = "World"_hello; // 添加 "Hello, "std::cout << greeting << std::endl; // 输出 "Hello, World"return 0;
}
字符串和长度字面量
C++20 前,可以通过传递字符串和长度参数实现更灵活的功能:
#include <iostream>// 自定义字面量,打印字符串和长度
void operator"" _log(const char* str, size_t len) {std::cout << "String: " << str << ", Length: " << len << std::endl;
}int main() {"Hello World"_log; // 输出 String: Hello World, Length: 11return 0;
}
C++自定义字面量也可以给变量赋予直接的语义信息,但是功能比较单一,而Strong Type通过类的封装,可以实现更复杂的功能。
Strong Type 和 C++字面量结合
#include <iostream>// 定义强类型 Distance
struct Distance {explicit Distance(double meters) : meters_(meters) {}double getMeters() const { return meters_; }
private:double meters_;
};// 自定义字面量
constexpr Distance operator"" _km(long double value) {return Distance(static_cast<double>(value * 1000.0));
}int main() {Distance d = 1.5_km; // 使用字面量创建强类型对象std::cout << "Distance: " << d.getMeters() << " meters" << std::endl; // 输出 1500 metersreturn 0;
}
总结
据说美国航空航天局火星气候探测者号的失联事故是因为代码中两种测量系统不匹配导致的(https://en.wikipedia.org/wiki/Mars_Climate_Orbiter), 如果能采取上面的编程技术,或许能避免这种事故的产生,当然这是后话。
下面总结一下上面编程技巧:
优点:
- 提高类型安全性。
- 增强代码可读性。
- 防止逻辑错误。
缺点:
- 增加一定的代码复杂性。
- 性能开销(通常可以忽略)。
我将在下一篇中对上面的NamedType源码进行一些解读。
相关文章:
C++ 编程技巧之StrongType(1)
最近看到一个NamedType的开源库,被里面的Strong Type这个概念和里面的模版实现给秀了一脸,特此总结学习一下 GitHub - joboccara/NamedType: Implementation of strong types in C C本身是一种强类型语言,类型包括int、double等这些build i…...
芯片测试-smith圆图
smith圆图 💢smith圆图的故事💢💢smith圆图中的各部分来历💢💢公式推导💢💢等电阻圆特点💢💢等电抗圆💢💢等电抗圆特点💢 Ὂ…...
HTML技术深度解析:构建现代网页的基石
引言 HTML(HyperText Markup Language,超文本标记语言)是构建网页和网上应用的标准标记语言。随着互联网技术的飞速发展,HTML已经成为前端开发中不可或缺的核心技术之一。本文将深入探讨HTML的基本概念、核心元素、最新发展以及在…...
Leecode刷题C语言之判断是否可以赢得数字游戏
执行结果:通过 执行用时和内存消耗如下: bool canAliceWin(int* nums, int numsSize) {int single_digit_sum 0;int double_digit_sum 0;for (int i 0; i < numsSize; i) {if (nums[i] < 10) {single_digit_sum nums[i];} else {double_digit_sum nums[…...
Ubuntu 关机命令
在 Ubuntu 系统中,有几种方法可以关机。以下是常用的关机命令及其说明: 1. 使用 shutdown 命令 shutdown 命令是最常用和最灵活的关机方式。它可以设置定时关机,并且可以发送警告消息给所有登录用户。 立即关机 sudo shutdown now定时关机…...
数据采集中,除了IP池的IP被封,还有哪些常见问题?
在数据采集的过程中,代理IP池的使用无疑为我们打开了一扇通往信息宝库的大门。然而,除了IP被封禁这一常见问题外,还有许多其他问题可能影响数据采集的效果。本文将探讨在数据采集中,除了IP被封之外,还可能遇到的一些常…...
【Anaconda】 创建环境报错:CondaHTTPError: HTTP 000 CONNECTION FAILED for url
问题描述 使用 Anaconda 创建环境时报错: CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/free/noarch/repodata.json.bz2> Elapsed: -An HTTP error occurred when trying to retrieve this URL. HTTP errors are o…...
社交电商破局之“2+1 链动模式 O2O 商城小程序源码”赋能流量困境突围
摘要:本文聚焦于当下商家在流量困境中挣扎的现状,剖析传统电商高流量成本、平台流量获取难等痛点,阐述私域流量池兴起的缘由与价值。重点探究“21 链动模式 O2O 商城小程序源码”如何融入社交电商架构,通过创新机制与线上线下融合…...
【ArcGIS Pro微课1000例】0062:ArcGIS Pro3.3.1中文版安装教程(附安装包下载)
本文讲述ArcGIS Pro3.3.1中文版安装教程(附安装包下载)。 文章目录 一、ArcGIS Pro3.3.1中文版下载二、ArcGIS Pro3.3.1中文版安装一、ArcGIS Pro3.3.1中文版下载 【订阅专栏】,获取完整安装包及专栏配套实验数据。下载后解压,如下图所示: 二、ArcGIS Pro3.3.1中文版安装…...
Linux - web服务器
四、web服务器 1、基础知识 URL:Uniform Resource Locator,统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。 网址格式:<协议>://<主机或主机名&g…...
设计模式-适配器模式-注册器模式
设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…...
减速机润滑油更换的最佳周期是多久?
减速机是工业设备中的重要组成部分,润滑油的使用对于其正常运转和寿命具有至关重要的作用。那么,减速机多久更换一次润滑油呢?实际上,减速机润滑油的更换周期受多种因素影响,以下是一些具体的更换周期建议:…...
程序执行堆栈执行模拟
所有的文件都是在硬盘(磁盘)上,调用时先调用javac指令的jdk编译成.class然后被java指令的jre送到内存中,java在内存中有自己的一片区域叫JVM,编译进来的文件首先进入方法区。 staitc的属性就是在进入内存的时候开辟了一…...
《Python基础》之数据加密模块hashlib的用法
目录 一、简介 二、用法 步骤一、导入hashlib库 步骤二、创建哈希对象 步骤三、往哈希对象中传值 1、可以在创建对象的时候传值 2、使用updata传值 步骤四、获取经过哈希对象加密后的值 三、注意事项 1、编码问题 2、安全性 3、多次传值 四、总结 一、简介 hashli…...
安装Fcitx5输入框架和输入法自动部署脚本(来自Mark24)-Ubuntu通用
在Ubuntu22.04上安装rime中文输入法的基本教程 上述文章接近废弃。 使用新逻辑配置基本的Fcitx5的输入法。 安装 第一步,下载相关组件 sudo nala install vim sudo nala install ruby sudo nala install fcitx5-rime第二步,设置语言为Fcitx5 而非 默认…...
【IMF靶场渗透】
文章目录 一、基础信息 二、信息收集 三、flag1 四、flag2 五、flag3 六、flag4 七、flag5 八、flag6 一、基础信息 Kali IP:192.168.20.146 靶机IP:192.168.20.147 二、信息收集 Nmap -sP 192.168.20.0/24 Arp-scan -l nmap -sS -sV -p- -…...
Zookeeper选举算法与提案处理概览
共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法,提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为: 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为,如进程崩溃,只要…...
深入了解 Adam 优化器对显存的需求:以 LLaMA-2 7B 模型为例 (中英双语)
中文版 深入了解 Adam 优化器对显存的额外需求:模型参数与优化器状态的显存开销分析 在深度学习模型的训练过程中,显存是一个关键的资源,尤其在处理大型语言模型或深度神经网络时。训练时的显存需求不仅包括模型参数本身,还涉及…...
数据分析学习
数据分析的定义 数据分析是通过对收集到的数据进行清理、转换、建模、分析和解释,从中提取有用的信息和洞察,以帮助做出更好的决策。数据分析可以应用于各种领域,比如商业、金融、医疗、市场营销等,目的是通过数据来发现模式、趋…...
PaddleOCR:一款高性能的OCR工具介绍
一、引言 随着人工智能技术的不断发展,光学字符识别(OCR)技术在各行各业得到了广泛应用。OCR技术能够将图片、扫描件等非结构化数据中的文字信息提取出来,转换为可编辑的文本格式。在我国,百度开源了一款优秀的OCR工具…...
Transformers快速入门代码解析(一):注意力机制——Attention:Scaled Dot-product Attention
Attention:Scaled Dot-product Attention 引言Scaled Dot-product Attention代码 引言 请注意!!!本博客使用了教程Transformers快速入门中的全部代码!!! 只在我个人理解的基础上为代码添加了注释…...
Git中HEAD、工作树和索引的区别
在Git版本控制系统中,HEAD、工作树(Working Tree)和索引(Index)是三个非常重要的概念,它们分别代表了不同的状态或区域,下面我将对这三个概念进行详细的解释。 HEAD 定义:HEAD是一…...
【python量化教程】如何使用必盈API的股票接口,获取最新实时交易数据
实时交易数据简介 股票实时交易数据涵盖股票价格、成交量、涨跌幅等多类信息。其在股票交易中极为关键,高速准确的数据对各方意义重大。投资者可借此及时捕捉机会、优化策略与降低风险;实时准确的实时交易数据是股票市场有效运转的核心要素之一。 使用…...
【C++】动态内存与智能指针——shared_ptr 和 new 结合使用
12.1.3 shared_ptr 和 new 结合使用 如上文所述,如果我们不初始化一个智能指针,那么它将会被初始化为一个空指针(需要注意的是,智能指针与普通指针在此处有着非常明显的区别。如果只声明某个类型的普通指针,而不对它进…...
遥感数据集:FTW全球农田边界和对应影像数据,约160万田块边界及7万多个样本
Fields of The World (FTW) 是一个面向农业田地边界实例分割的基准数据集,旨在推动机器学习模型的发展,满足全球农业监测对高精度、可扩展的田地边界数据的需求。该数据集由kerner-lab提供,于2024年8月28日发布,主要特征包括&…...
马斯克的 AI 游戏工作室:人工智能与游戏产业的融合新纪元
近日,马斯克在 X 平台(前身为 Twitter)发文称,“太多游戏工作室被大型企业所拥有,xAI 将启动一个 AI 游戏工作室,让游戏再次变得精彩”。这一言论不仅展示了马斯克对游戏行业现状的不满,也揭示了…...
URDF(描述机器人模型)和SDF(Gazebo中用于描述仿真环境)
使用URDF(Unified Robot Description Format) URDF是ROS中用于描述机器人模型的XML格式文件。你可以使用XML文件定义机器人的几何形状、惯性参数、关节和链接等。 示例URDF文件(my_robot.urdf): <?xml version&…...
力扣380:O(1)时间插入、删除和获取随机数
实现RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。bool remove(int val) 当元素 val 存在时࿰…...
【C++boost::asio网络编程】有关socket的创建和连接的笔记
socket的创建和连接 tcp客户端创建端点tcp服务端创建端点创建socket创建TCP 服务器端的 acceptor 套接字创建 acceptor 套接字并绑定客户端连接到服务器通过ip地址解析通过域名解析 服务端接收新连接 tcp客户端创建端点 int client_end_point() {std::string raw_ip_address …...
超级灵感:前端页面功能统一管理方案
前端页面功能统一管理方案 引言 我和朋友聊天想到一个灵感,关于支付状态机管理,这个类可以让我们知道具体上一个状态和下一个状态,这是由于那个事件触发改变,这个功能设计非常好! 从而讨论出为什么我们不能把某一个…...
网站数据库 权限设计/交换链接营销实现方式解读
1、项目背景 https://passport.csdn.net/login CSDN登录页面 2、功能实现 自动运行用例 自动生成测试报告 自动断言与截图 自动将最新测试报告发送到指定邮箱 数据,页面元素分离 PageObjectUnittestddt数据驱动用例 执行日志、分布式执行 3、项目架构…...
重庆所有做网站的公司/做微商怎么找客源加人
1、time.Sleep 可以直接sleep需要的时间之后,在执行,调度器会把当前协程置为GWaiting状态,放入定时器阻塞堆,是一个小顶堆,不断去堆顶元素 2、time.Timer 简单使用 fmt.Println("now time",time.Now().F…...
一个企业做网站的意义/2022百度搜索风云榜
使用php下载图片的时候遇到md5问题, 源图片通过http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png下载,原图和curl获取到图片源时的md5一致,但使用php中的fwrite后就不行.问sf的朋友们: 如何用PHP保存图片的时候使得md5值不变!代码如:/*** 加载图片**/$save_d…...
廉洁四川官方网权威发布/汕头seo推广外包
本文为美国罗切斯特理工学院(作者:Sandeep Aswath Narayana)的硕士论文,共56页。 硅工艺技术的不断改进使得在单个芯片上集成数百个核成为可能。然而,功耗和散热已经成为设计这些大规模多核芯片的主要限制,…...
典型b2c模式的网站/怎样做品牌推广
硬盘分区不是自己想要的?分区容量不够需要扩容?电脑硬盘已经分好区,需要调整分区大小怎么办?下载分区助手专业版易我分区大师专业版软件,帮助管理磁盘分区,调整磁盘布局。 官网详情访问: https://www.ease…...
北京市城乡建设委员会门户网站/新品牌推广策略
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼请问一下为什么用串口来连接两台计算机,做发送与接收,可是却没反应呢?帮我看下程序,行么?发送端的clear;sserial(com2,baudrate,1200);set(s, Parity, none) ; % Set parity as noneset(s, Databits, 8) ; % set the n…...