当前位置: 首页 > news >正文

C++使用策略模式,减少使用switch...case...

目录

  • 原理
  • 函数
  • 类+模板函数
    • 使用switch...case...
    • 不使用switch...case...
  • 知识点
    • decltype
    • std::remove_reference

原理

在这里插入图片描述

函数

#include <iostream>
#include <functional>
#include <map>void fun1(int a, int b)
{std::cout << "fun1 : a ="<<a<<"	b ="<<b;
}void fun2(int a, int b)
{std::cout << "fun2 : a =" << a << "	b =" << b;
}int main()
{// 可以改变这个值来调用不同的函数int id = 1;#if 0switch (id){case 1:fun1(0, 0);break;case 2:fun1(0, 0);break;}
#endifstd::map<int, std::function<void(int,int)>> functionMap;functionMap[1] = [](int a, int b) { fun1(a,b); };functionMap[2] = [](int a, int b) { fun2(a, b); };if (functionMap.find(id) != functionMap.end()) {// 调用对应的函数并传递参数functionMap[id](0,0);}else {std::cout << "Invalid id" << std::endl;}return 0;
}

类+模板函数

因为工作职位低,无权对父类进行修改;
业务上又大量使用switch…case…操作模板函数;搞得代码量暴涨!

使用switch…case…

#include <iostream>
#include <functional>
#include <map>
#include <string>
#include <tuple>
#include <type_traits>// 因为没有Equip的修改权限
struct Equip {std::string code;       //装备
};struct FATable:public Equip {int idFA;               //方案IDstd::string nameId;     //名称IDstd::string equipId;    //装备IDint equipNum;           //装备数量
public:void write(int info) {std::cout << "FATable = " << info;};
};struct NTable {std::string name;       //装备名称std::string nameId;     //装备IDint classify;           //分类ID
public:void write(int info) {std::cout << "NTable = " << info;};
};struct CTable {int classify;           //分类IDstd::string className;  //分类名称
public:void write(int info) {std::cout << "CTable  = "<< info;};
};template<typename T>
inline void writeIn(int info) {T().write(info);
};int main()
{// 可以改变这个值来调用不同的函数const int id = 1;#if 1switch (id){case 0:writeIn<FATable>(0);break;case 1:writeIn<NTable>(0);break;case 2:writeIn<CTable>(0);break;}
#endifreturn 0;
}

不使用switch…case…

#include <iostream>
#include <functional>
#include <map>
#include <string>
#include <tuple>
#include <type_traits>// 因为没有Equip的修改权限
struct Equip {std::string code;       //装备
};struct FATable:public Equip {int idFA;               //方案IDstd::string nameId;     //名称IDstd::string equipId;    //装备IDint equipNum;           //装备数量
public:void write(int info) {std::cout << "FATable = " << info;};
};struct NTable {std::string name;       //装备名称std::string nameId;     //装备IDint classify;           //分类ID
public:void write(int info) {std::cout << "NTable = " << info;};
};struct CTable {int classify;           //分类IDstd::string className;  //分类名称
public:void write(int info) {std::cout << "CTable  = "<< info;};
};template<typename T>
inline void writeIn(int info) {T().write(info);
};int main()
{// 可以改变这个值来调用不同的函数const int id = 1;std::tuple<FATable, NTable, CTable> g_type = { FATable(), NTable(), CTable()};// 使用 decltype 来获取 g_type 中的元素类型,并将其命名为 _mT。using  _mT = decltype(std::get<id>(g_type));// 使用 std::remove_reference 来移除 _mT 类型的引用修饰符,将结果命名为 CleanType。using CleanType = typename std::remove_reference<_mT>::type;// 将 CleanType 作为模板参数传递writeIn<CleanType>(0);return 0;
}

知识点

decltype

decltype 是 C++11 引入的一个关键字,用于获取表达式的类型。它可以用于编译时推导表达式的类型,而不需要显式地指定类型。

  • 以下是 decltype 的一些重要知识点:

decltype 的语法:decltype(expression)

  • expression 是一个表达式,可以是变量、函数调用、成员访问等。

  • decltype 的返回类型:

如果 expression 是一个标识符或类成员访问表达式,decltype 返回该标识符或成员的类型。

如果 expression是一个函数调用表达式,decltype 返回函数的返回类型。

如果 expression是一个右值表达式,decltype返回右值的类型。

如果 expression 是一个左值表达式,decltype 返回左值的引用类型。

  • decltype 的应用场景:

在模板编程中,可以使用 decltype 推导模板参数的类型,以便在编译时确定类型。

可以使用 decltype 推导 lambda表达式的返回类型。

可以使用 decltype 推导复杂表达式的类型,避免手动指定类型。

-以下是一些使用 decltype 的示例:

	int x = 42;decltype(x) y;					// y 的类型为 intstd::vector<int> vec = { 1, 2, 3 };decltype(vec.size()) size;		// size 的类型为 std::vector<int>::size_typeauto lambda = [](int a, int b) -> int { std::cout << "a + b  = " << a + b;return a + b; };decltype(lambda) func = lambda;	// func 的类型为 lambda 表达式的类型func(1,1);template <typename T, typename U>auto add(T t, U u) -> decltype(t + u) {return t + u;}auto result = add(3, 4.5);		// result 的类型为 double
#include <iostream>
#include <typeinfo>
int main() {auto f = []()->void {std::cout << "hello---19" << std::endl;};using FunctionType = decltype(f);              // 使用 decltype(f) 定义类型别名 FunctionTypestd::cout << typeid(f).name() << std::endl;    // 输出类型名称std::cout << typeid(FunctionType).name() << std::endl;  // 输出类型别名的名称FunctionType func = f;                          // 使用类型别名创建变量,并将 f 赋值给它func();  // 调用函数对象/*使用 decltype 推导出的函数类型,不能直接声明一个未初始化的变量并调用它错误用法:FunctionType func;func();*/return 0;
}

在这里插入图片描述
在这里插入图片描述

std::remove_reference

std::remove_reference 是 C++ 标准库中的一个模板元函数,用于移除类型的引用修饰符
当您使用std::remove_reference 时,它将返回一个新类型,该类型是从给定类型中移除了引用修饰符的版本。

  • 以下是 std::remove_reference 的示例用法:
#include <iostream>
#include <type_traits>int main() {// 定义一个带有引用修饰符的类型using TypeWithReference = int&;// 使用 std::remove_reference 移除引用修饰符using TypeWithoutReference = std::remove_reference<TypeWithReference>::type;// 输出移除引用修饰符后的类型名称std::cout << "Type without reference: " << typeid(TypeWithoutReference).name() << std::endl;return 0;
}

在这个示例中,TypeWithReference 是一个带有引用修饰符的类型,然后我们使用 std::remove_reference 来移除引用修饰符,得到了 TypeWithoutReference。最后,我们输出了移除引用修饰符后的类型名称。

请注意,在 C ++14及更高版本中,你可以使用简化形式 std :: remove _ reference _ t 代替
typename std :: remove _ reference < T >:: type以缩短代码:

using CleanType = std::remove_reference_t<TypeWithReference>;

这提供了相同的结果,即从类型中去除引用

相关文章:

C++使用策略模式,减少使用switch...case...

目录 原理函数类模板函数使用switch...case...不使用switch...case... 知识点decltypestd::remove_reference 原理 函数 #include <iostream> #include <functional> #include <map>void fun1(int a, int b) {std::cout << "fun1 : a "<…...

.NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)

WebAppDbTest 项目准备 项目准备1、.net cli 创建项目2、nuget 包引用和项目结构2.1、项目添加相关 nuget 包2.2、WebAppDbTest 项目结构 3、项目代码说明3.1、CSharp/C# 类文件说明3.2、json 配置文件说明 4、项目运行预览 数据库 .db 文件准备1、创建 SQLite 数据库1.1、在 W…...

2024 年,新程序员如何与AI共赢!!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

Debian 系统镜像下载

最近在看一些网络相关的文章需要用到 debian 11.x 的系统网上找了好多都发下载&#xff0c;在官网看一下 有个 11.8 的版本我无法下载&#xff0c;提示被最新的 debian-12.4.0 所代替&#xff0c;于是找到了这个链接 Index of /cdimage/unofficial/non-free/cd-including-fi…...

数据结构和算法(全)

1.了解数据结构和算法 1.1 二分查找 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;从而确定应该在左半部分还是右半部分继续查找。这个…...

Vue项目中WebSocket封装

WEBSOCKET 封装引入初始化使用 封装 utils下建立WebSocketManager.js class WebSocketManager {constructor() {this.url null;this.websocket null;this.isConnected false;this.listeners {onopen: [],onmessage: [],onclose: [],onerror: [],};this.reconnectionOptio…...

018 OpenCV 人脸检测

目录 一、环境 二、分类器原理 2.1、概述 2.2、工作原理 三、人脸检测代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、分类器原理 CascadeClassifier是OpenCV&#xff08;开源计算机视觉库&#xff09;中的一个强大的类…...

Etcd实战(一)-部署etcd集群

1 概述 etcd是一个高可用的分布式键值存储系统&#xff0c;是CoreOS&#xff08;现在隶属于Red Hat&#xff09;公司开发的一个开源项目。它提供了一个简单的接口来存储和检索键值对数据&#xff0c;并使用Raft协议实现了分布式一致性。etcd广泛应用于Docker、Kubernetes等分布…...

Python绘制一个简单的圣诞树

在Python中,你可以使用基本的打印语句和循环来绘制一个简单的圣诞树。以下是一个例子: def draw_christmas_tree(height):for i in range(height):print( * (height - i - 1) +...

【CANoe】CANoe中使用RS232

文章目录 1、CANoe中自带示例2、示例讲解2.1CANoe自带Port A和Port B通讯2.2CANoe自带Port A和串口助手通讯 1、CANoe中自带示例 我使用的事CANoe12&#xff0c;RS232路径如下&#xff1a; C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 12.0.75\IO_HIL\RS23…...

Springboot内置Tomcat线程数优化

Springboot内置Tomcat线程数优化 # 等待队列长度&#xff0c;默认100。队列也做缓冲池用&#xff0c;但也不能无限长&#xff0c;不但消耗内存&#xff0c;而且出队入队也消耗CPU server.tomcat.accept-count1000 # 最大工作线程数&#xff0c;默认200。&#xff08;4核8g内存…...

vue+django 开发环境跨域前后端联调配置

vue环境是127.0.0.1:8080&#xff0c;django环境是127.0.0.1:8000 要解决url相对路径和Axios跨域权限问题。 注意&#xff1a;程序发起了一个 POST 请求&#xff0c;但请求的 URL 没有以斜杠结尾。Django 默认设置是无法执行重定向到带斜杠 URL的。例如&#xff1a;url http:/…...

Apache+mod_jk模块代理Tomcat容器

一、背景介绍 最近在看Tomcat运行架构原理, 正好遇到了AJP协议(Apache JServ Protocol). 顺道来研究下这个AJP协议和具体使用方法. 百度百科是这么描述AJP协议的: AJP&#xff08;Apache JServ Protocol&#xff09;是定向包协议。因为性能原因&#xff0c;使用二进制格式来传输…...

Nginx访问FTP服务器文件的时效性/安全校验

背景 FTP文件服务器在我们日常开发中经常使用&#xff0c;在项目中我们经常把FTP文件下载到内存中&#xff0c;然后转为base64给前端进行展示。如果excel中也需要导出图片&#xff0c;数据量大的情况下会直接返回一个后端的开放接口地址&#xff0c;然后在项目中对接口的参数进…...

【VSCode】自定义配置

VSCode自定义配置 Visual Studio Code (VSCode) 是一个强大的开源代码编辑器&#xff0c;支持丰富的自定义配置。下面是一些常见的自定义配置选项&#xff0c;你可以根据个人喜好和工作流程进行调整&#xff1a; 1. 主题和配色方案: 在 “settings.json” 中设置&#xff1a…...

SpringBoot整合Kafka (一)

&#x1f4d1;前言 本文主要讲了SpringBoot整合Kafka文章⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#xff1a;努力一点&#xff0c;优秀一点 目录 文章目录 &…...

随机分词与tokenizer(BPE->BBPE->Wordpiece->Unigram->sentencepiece->bytepiece)

0 tokenizer综述 根据不同的切分粒度可以把tokenizer分为: 基于词的切分&#xff0c;基于字的切分和基于subword的切分。 基于subword的切分是目前的主流切分方式。subword的切分包括: BPE(/BBPE), WordPiece 和 Unigram三种分词模型。其中WordPiece可以认为是一种特殊的BPE。完…...

成都工业学院Web技术基础(WEB)实验四:CSS3布局应用

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考&#xff0c;前端变化比较大&#xff0c;按照要求&#xff0c;只能做到像&#xff0c;不能做到一模一样 3、图片和文字仅为示例&#xff0c;需要自行替换 4、如果代码不满足你的要求&#xff0c;请寻求其他的…...

TikTok科技趋势:平台如何引领数字社交革命?

TikTok作为一款颠覆性的短视频应用&#xff0c;不仅改变了用户的娱乐方式&#xff0c;更在数字社交领域引领了一场革命。本文将深入探讨TikTok在科技趋势方面的引领作用&#xff0c;分析其在数字社交革命中的关键角色&#xff0c;以及通过技术创新如何不断满足用户需求&#xf…...

【上海大学数字逻辑实验报告】六、时序电路

一、 实验目的 掌握同步二进制计数器和移位寄存器的原理。学会用分立元件构成2位同步二进制加计数器。学会在Quartus II上设计单向移位寄存器。学会在Quartus II上设计环形计数器。 二、 实验原理 同步计数器是指计数器中的各触发器的时钟脉冲输入端连接在一起&#xff0c;接…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...