C++ 编程技巧之StrongType(2)

news2024/12/19 9:18:50

NamedType源码解读

上一篇博文中介绍了Strong Type的一些基本思想,并提到了开源库NamedTypeC++ 编程技巧之StrongType(1)-CSDN博客,本篇文章我们来分析一下NamedType 的源码实现。

NamedType用法

我们先看几个NamedType的简单用法

TEST_CASE("Addable")
{
    using AddableType = fluent::NamedType<int, struct AddableTag, fluent::Addable>;
    AddableType s1(12);
    AddableType s2(10);
    REQUIRE((s1 + s2).get() == 22);
    REQUIRE((+s1).get() == 12);
}

TEST_CASE("Printable")
{
    using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::Printable>;

    std::ostringstream oss;
    oss << StrongInt( 42 );
    CHECK(oss.str() == "42");
}

TEST_CASE("PreIncrementable")
{
    using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::PreIncrementable>;
    StrongInt a{1};
    StrongInt b = ++a;
    CHECK( a.get() == 2 );
    CHECK( b.get() == 2 );
}

自定义的NamedType通过选择一些继承的Skill类,就具有了相应的增强技能,这是一种通过继承来获取基类能力的方式。

NamedType实现解析

首先看一下NamedType模版类的定义,开门被雷暴击的感觉,这fucking啥玩意?

template <typename T, typename Parameter, template <typename> class... Skills>
class FLUENT_EBCO NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
{
public:
    using UnderlyingType = T;
……
}

模板参数详解

template <typename T, typename Parameter, template <typename> class... Skills>
class NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
模板参数说明:

类型T:

  • 表示一个基础类型(UnderlyingType),该类型表示底层存储的实际数据类型,例如 intstd::string

Parameter:

  • 一个辅助参数,用于区分不同的 NamedType 实例,即使它们具有相同的底层类型 T

template <typename> class... Skills:

  • 是一个模板类的 参数包,表示可以传入多个模板类作为参数。
  • 这些模板类必须是形如 template <typename> class Skill 的单参数模板。
  • 参数包 Skills 支持任意数量的模板类,可以为空。
类的继承
class NamedType : public Skills<NamedType<T, Parameter, Skills...>>...

继承分析:

  • 这里 NamedType 通过 ... 展开继承了 所有 Skills 模板类实例化后的类型
  • 每个 Skill 模板类会以当前的 NamedType 类型作为其模板参数进行实例化:
Skills<NamedType<T, Parameter, Skills...>>  //CRPT模版
  • 这种继承机制允许将多种功能(由 Skills 模板类定义)混入到 NamedType 中,实现 功能扩展

定义一个 NamedType实例:

using StrongInt = fluent::NamedType<int, struct StrongIntTag, fluent::Printable, fluent::Addable>;

class NamedType : public Printable<NamedType<int, StrongIntTag, Printable, Addable>>,
public Addable<NamedType<int, StrongIntTag, Printable, Addable>> {
...
};

class Printable<NamedType<int, StrongIntTag, Printable, Addable>> : 
crtp<NamedType<int, StrongIntTag, Printable, Addable>, Printable>

class Addable<NamedType<int, StrongIntTag, Printable, Addable>> : 
crtp<NamedType<int, StrongIntTag, Printable, Addable>, Addable>

成员类型定义

using UnderlyingType = T;
  • 定义 UnderlyingType,便于外界访问实际存储的数据类型。

构造函数

NamedType() = default;

默认构造函数,允许空对象的创建。

explicit constexpr NamedType(T const& value) noexcept(std::is_nothrow_copy_constructible<T>::value)
    : value_(value) {}
  • 使用左值构造 NamedType 实例。
  • 如果 T 可无异常复制,则构造函数被标记为 noexcept
template <typename T_ = T, typename = IsNotReference<T_>>
explicit constexpr NamedType(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value)
    : value_(std::move(value)) {}
  • 使用右值构造 NamedType 实例。
  • 为避免引用类型的冲突,通过 IsNotReference 限制 T 必须是非引用类型。

访问接口

constexpr T& get() noexcept;
constexpr std::remove_reference_t<T> const& get() const noexcept;
  • 提供两种 get 方法:
  • get() 返回底层类型的非 const 引用。get() const 返回底层类型的 const 引用。

类型转换

using ref = NamedType<T&, Parameter, Skills...>;
operator ref() { return ref(value_); }
  • 将当前 NamedType 实例隐式转换为一个引用类型(NamedType<T&, Parameter, Skills...>)。
  • 这使得可以将 NamedType 对象直接传递到需要引用的地方。

argument 内嵌结构体

struct argument {
    NamedType operator=(T&& value) const {
        return NamedType(std::forward<T>(value));
    }

    template <typename U>
    NamedType operator=(U&& value) const {
        return NamedType(std::forward<U>(value));
    }
    // ...
};
  • 内嵌结构体 argument 用于支持命名参数的语法。
  • 通过 operator= 重载,创建一个新的 NamedType 实例。

这个argument在这里有点莫名其妙,但是还是有点东西,我们后面再讲。

私有成员

T value_;
  • 存储实际的数据值,类型为模板参数 T

辅助工具解析

make_named

template <template <typename T> class StrongType, typename T>
constexpr StrongType<T> make_named(T const& value) {
    return StrongType<T>(value);
}
  • 提供一种简便的方法,通过给定值创建 NamedType
  • 适用于代码中需要快速创建 NamedType 的场景。
  • 可以类比make_unique_ptr<>来理解

Skills拓展类实现

  • Incrementable<T>,可增性
  • PreIncrementable<T>, ++i
  • PostIncrementable<T>, i++
  • Decrementable<T>,可减性
  • PreDecrementable<T>, --i
  • postDecrementable<T>, i --
  • Addable<T>, a+b
  • Subtractable<T> , a -b
  • Multiplicable<T> a*b
  • Divisible<T> a/b
  • Modulable<T> a%b
  • BitWiseInvertable<T>
  • BitWiseAndable<T>
  • BitWiseOrable<T>
  • BitWiseXorable<T>
  • BitWiseLeftShiftable<T>
  • BitWiseRightShiftable<T>
  • Comparable<T>
  • Printable<T>
  • Hashable<T>

这些Skill的实现也很简单,就是对一些简单运算符或者操作的封装,例如Printable:

template <typename T>
struct Printable : crtp<T, Printable>
{
    static constexpr bool is_printable = true;

    void print(std::ostream& os) const
    {
        os << this->underlying().get();
    }
};

template <typename T>
struct PostIncrementable : crtp<T, PostIncrementable>
{
    IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN

    FLUENT_CONSTEXPR17 T operator++(int)
    {
        return T(this->underlying().get()++);
    }

    IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END
};

NamedType 是一个用于实现强类型(strong type)的模板类,结合了多个模板参数和特性以实现灵活的功能扩展。通过对构造函数、类型转换、和技能(Skills)进行封装,这个类的设计旨在提供一种类型安全且高效的方式来定义具有特定含义的类型。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis篇】Set和Zset 有序集合基本使用

目录 Set 基本命令 sadd SMEMBERS SISMEMBER SCARD 返回值&#xff1a; SPOP SMOVE SREM 集合间操作 交集&#xff1a; 并集&#xff1a; 差集&#xff1a; ​编辑 内部编码 使用场景&#xff1a; Zset 有序集合 Zset基本命令 ZADD ZCARD ZCOUNT ZRANGE …

ASRPRO学习笔记一之语音模型位置和语音替换

一、语音替换的步骤 1、扬声器录音 打开GoldWave,点击工具栏中的蓝色控制属性按钮&#xff0c;点击设备&#xff0c;选择扬声器&#xff0c;点击ok。打开电脑上的网易云音乐&#xff0c;点击红色的录制按钮&#xff0c;开始录制音乐&#xff0c;在网易云音乐上点击播放音乐,录…

2.12.顺序表和链表的比较

一.逻辑结构&#xff1a; 二.物理结构/存储结构&#xff1a; 1.顺序表&#xff1a; 优点&#xff1a;顺序表采用顺序存储的方式实现了线性表&#xff0c;由于采取了顺序存储&#xff0c;而且各个数据元素的内存大小相等&#xff0c;因此只需要知道该顺序表的起始地址即可立即找…

OSLC助力系统工程的全生命周期整合 (转)

本文作者胡振超&#xff0c;上海交通大学博士研究生。课题牵头人为鲁金直&#xff0c;瑞典皇家理工学院博士。本项目有Ericsson.SE高级顾问顾文卿&#xff0c;中科蜂巢相关工程师相关工程师所提供的基于多架构建模Karma语言的自主多架构建模工具MetaGraph、OSLC数据整合工具Dat…

electron打包linux环境

注意:新版的electron已经不支持在win上直接打包Linux的环境了,服务会卡住,会一直生成文件占用磁盘(我发现的时候占了我100G&#xff0c;而且文件夹很深&#xff0c;找了java代码while循环&#xff0c;好不容易删除的o(╥﹏╥)o) electron有一个专门打包的docker镜像&#xff0c…

活动预告|云原生创新论坛:知乎携手 AutoMQ、OceanBase、快猫星云的实践分享

近年来&#xff0c;云原生技术迅猛发展&#xff0c;成为企业数字化转型的关键动力&#xff0c;云原生不仅极大地提升了系统的灵活性和可扩展性&#xff0c;还为企业带来了前所未有的创新机遇。 12 月 28 日 知乎携手 AutoMQ、OceanBase 和快猫星云推出“云原生创新论坛”主题的…

AMS1117芯片驱动电路·降压芯片的驱动电路详解

编写不易&#xff0c;仅供学习&#xff0c;请勿搬运&#xff0c;感谢理解 AMS1117驱动电路 很常用的一种LDO降压芯片&#xff0c;LDO(Low Dropout Regulator)降压芯片是线性稳压器&#xff0c;这种IC因为内部集成的不是开关电路&#xff0c;只能将输入与输出的电压差值通过内部…

[论文阅读]Universal and transferable adversarial attacks on aligned language models

Universal and transferable adversarial attacks on aligned language models http://arxiv.org/abs/2307.15043 图 1&#xff1a;Aligned LLMs 不是对抗性 Aligned。我们的攻击构建了一个单一的对抗性提示&#xff0c;该提示始终绕过最先进的商业模式&#xff08;包括 ChatG…

【HarmonyOS之旅】HarmonyOS开发基础知识(一)

目录 1 -> 应用基础知识 1.1 -> 用户应用程序 1.2 -> 用户应用程序包结构 1.3 -> Ability 1.4 -> 库文件 1.5 -> 资源文件 1.6 -> 配置文件 1.7 -> pack.info 1.8 -> HAR 2 -> 配置文件简介 2.1 -> 配置文件的组成 3 -> 配置文…

DDoS工作原理

原理 原理解释1 DDoS攻击的核心原理是利用大量的恶意请求占用过多的资源&#xff0c;使目标系统无法处理正常的请求。 这些恶意请求可以包括数据包或请求&#xff0c;通常通过分布式网络进行发送&#xff0c;利用多个计算机或设备协同攻击。 这些被控制的计算机或设备被称为“…

搭建springmvc项目

什么是springmvc MVC它是一种设计理念。把程序按照指定的结构来划分: Model模型 View视图 Controller控制层 springmvc框架是spring框架的一个分支。它是按照mvc架构思想设计的一款框架。 springmvc的主要作用: 接收浏览器的请求数据&#xff0c;对数据进行处理&#xff0c;…

【USB-HID】“自动化键盘“ - 模拟键盘输入

目录 【USB-HID】"自动化键盘" - 模拟键盘输入1. 前言2. 模拟键盘2.1 STM32CubeMX 配置2.2 修改代码配置2.3 发送按键信息 3. 接收主机Setup数据3.1 获取PC下发的数据 4. 总结 【USB-HID】“自动化键盘” - 模拟键盘输入 1. 前言 对于模拟键盘的实现&#xff0c;网…

Scratch圣诞节作品 | 礼物快递大作战——限时挑战,传递圣诞惊喜! ✨

今天为大家推荐一款紧张又趣味十足的Scratch圣诞小游戏——《礼物快递大作战》&#xff01;由CreativeCatStudios制作&#xff0c;这款作品用简单的操作、快节奏的玩法&#xff0c;将圣诞节的礼物传递任务变成了一场冒险挑战&#xff01;更棒的是&#xff0c;这款游戏的源码可以…

Gin- Cookie\Session相关

Cookie&#xff0c;Session是什么&#xff1f; Cookie直译小饼干&#xff0c;是一些数据信息&#xff0c;类似于小型文本文件&#xff0c;存储在浏览器上。Cookie是进行第一次登录之后&#xff0c;由服务器创建后返回给浏览器的。之后&#xff0c;每当浏览器再次向同一服务器发…

uniapp 微信小程序 功能入口

单行单独展示 效果图 html <view class"shopchoose flex jsb ac" click"routerTo(要跳转的页面)"><view class"flex ac"><image src"/static/dyd.png" mode"aspectFit" class"shopchooseimg"&g…

uniapp开发微信小程序优化项目

问题一&#xff1a;对JS文件进行压缩 1、上传代码时自动压缩 2、运行时压缩压缩代码 3、以上2步不行可直接在开发者工具设置 二、 主包与vendor.js过大问题 1、配置 manifest.json 分包配置 与 组件懒加载配置 "lazyCodeLoading" : "requiredComponents" …

day50|DFS,BFS

深度优先遍历&#xff08;DFS&#xff09; 不撞南墙不回头算法 撞了之后就回退一步找别的路&#xff08;回溯算法&#xff09; 直到访问所有的顶点 注意&#xff1a;深度优先遍历的序列不是唯一的 若无向图非连通&#xff1a; 需要执行多次深度优先遍历 重要结论&#xff…

Linux系统安装部署Tomcat

1、进入Tomcat官网&#xff0c;官网地址&#xff1a;https://tomcat.apache.org/ 2、点击左侧Download下的Archives按钮 3、选择需要下载的版本 下载地址&#xff1a;https://archive.apache.org/dist/tomcat/ 4、点击自己需要下载的版本&#xff0c;我这里下载的是9.0.6 5、…

java全栈day17--Web后端实战(java操作数据库)

前言&#xff1a;本章应该是针对数据库基础讲解&#xff0c;数据的增删改查但是本人忘记对知识进行归纳总结就直接跳过&#xff0c;基本的内容都很简单&#xff0c;都是套式子使用。现在开始学习本章&#xff0c;很重要需要好好掌握。 一、使用的工具 二、JDBC 2.1概述 JDBC …

分立器件---运算放大器关键参数

运算放大器 关键参数 1、供电电压:有单电源电压、双电源电压,双电源电压尽量两个电源都接。如图LM358B,供电电压可以是20V或者是40V和GND。 2、输入偏置电流IB:当运放输出直流电压为零时,运放两个输入端流进或者流出直流电流的平均值。同向输入端电流IB+与反向输入端电流…