没用的cpp知识又增加了之--cpp11利用宏、模板以及lambda表达式实现python like的装饰器语义

news2024/11/19 18:35:00

等有时间了我再bb吧,先直接上码

msvc 2015 编译执行效果

在这里插入图片描述

用法

style1

int CCar::oilfeed(int degress)
DECORATED(logging<int>, ARGS(__FUNCTION__),
DECORATED(checkRotateSpeed<int>, ARGS(this, __FUNCTION__),
{
    m_n_rotat_speed += degress;
    return m_n_rotat_speed;
}))//前面又多少个装饰器就需要多少个),cpp只能这样了,想不出什么好的方法了

style2

void CCar::brake(int degress)
//建议还是用仿函数的方式实现装饰器封装性更好,如果舍弃函数类型的装饰器的话就可以少一个宏参数占位了,
//由于没有针对void作为返回值的特例化实现,所以不能使用logging<void>,cpp11可以用类型提取结合重载来实现特例化值,cpp17可以通过if constexpr更简洁的实现,我这里为了兼容性更好所以使用cpp11的方式
//DECORATED(logging<void>, ARGS(__FUNCTION__),
DECORATED(CheckRotateSpeed<void>(this, __FUNCTION__),,
{
  m_n_rotat_speed -= degress;
  return m_n_rotat_speed;
})

完整测试代码 main.cpp

#include <QCoreApplication>
#include <functional>
#include <iostream>
#include <chrono>

//小米新车发布了,那就定义一个车吧
class CCar{
public:
    int oilfeed(int degress);
    void brake(int degress);
    int rotat_speed() const {return m_n_rotat_speed;}
private:
    int m_n_rotat_speed = 2000;
};

//定义一个函数装器
template <typename T>
T logging(std::function<T ()> func, std::string const &funcanme)
{
    //在调用被装饰函数之前的操作
    auto start = std::chrono::high_resolution_clock::now();
    std::cout <<"log before " << funcanme  << std::endl;
    auto const &ret = func();
    //在调用被装饰函数之后的操作
    // 获取当前时间
    auto end = std::chrono::high_resolution_clock::now();

    // 计算时间差
    std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    std::cout << "log after " << funcanme << ": elapsed time(s): " << time_span.count() << std::endl;
    return ret;
}

template<typename T>
T checkRotateSpeed(std::function<T ()> func, CCar const *obj, std::string const &funcanme)
{
    std::cout << "checkRotateSpeed before " << funcanme  << ", rotat_speed:" << obj->rotat_speed()  << std::endl;
    auto const &ret = func();
    std::cout << "checkRotateSpeed after "  << funcanme  << ", rotat_speed:" << obj->rotat_speed() << std::endl;
    return ret;
}

template<bool T>
//!
//! \brief The bool_trait struct
//! \usecase bool_trait<静态表达式->bool> 用于模板特例化
//!
struct bool_trait{};

//定义一个仿函数装饰器,无论是函数装饰器还是仿函数装饰器,第一个参数都得是std::function<T ()> 类型否则装饰器宏无法正常展开
template<typename T>
class CheckRotateSpeed{
public:
    CheckRotateSpeed(CCar const *obj, std::string const &funcanme)
        :m_p_obj(obj)
        ,m_str_funcanme(funcanme)
    {

    }

    T operator ()(std::function<T ()> func){
        return (*this)(func, bool_trait<std::is_same_v<T, void>> ());
    }

protected:
    inline void before()
    {
        //在调用被装饰函数之前的操作
        std::cout << "checkRotateSpeed before " << m_str_funcanme  << ", rotat_speed:"<< m_p_obj->rotat_speed()  << std::endl;
    }

    inline void after()
    {
        //在调用被装饰函数之前的操作
        std::cout << "checkRotateSpeed after " << m_str_funcanme  << ", rotat_speed:"<< m_p_obj->rotat_speed()  << std::endl;
    }

    T operator ()(std::function<T ()> func, bool_trait<false>){
        before();
        auto const &ret = func();
        after();
        return ret;
    }
    //针对 void 类型特例化代码
    T operator ()(std::function<T ()> func, bool_trait<true> ){
        before();
        func();
        after();
    }
private:

    CCar const *m_p_obj;
    std::string m_str_funcanme;
};

//启用装饰器语义宏定义
#define USE_DECORATOR
#ifdef USE_DECORATOR
//打包参数的宏,仿函数装饰器可以不使用
#define ARGS(...)\
    ,__VA_ARGS__

//装饰宏,其实就是用{}把代码块包起来
#define DECORATED(decorator, args, codeblock) \
{\
    return decorator( [&]() codeblock args);\
    }
#endif //USE_DECORATOR

int CCar::oilfeed(int degress)
DECORATED(logging<int>, ARGS(__FUNCTION__),
DECORATED(checkRotateSpeed<int>, ARGS(this, __FUNCTION__),
{
    m_n_rotat_speed += degress;
    return m_n_rotat_speed;
}))//前面又多少个装饰器就需要多少个),cpp只能这样了,想不出什么好的方法了

void CCar::brake(int degress)
//建议还是用仿函数的方式实现装饰器封装性更好,如果舍弃函数类型的装饰器的话据可以少一个宏参数占位了,
//由于没有针对void作为返回值的特例化实现,所以不能使用logging<void>,cpp11可以用类型提取结合重载来实现特例化值,cpp17可以通过if constexpr更简洁的实现
//DECORATED(logging<void>, ARGS(__FUNCTION__),
DECORATED(CheckRotateSpeed<void>(this, __FUNCTION__),,
{
  m_n_rotat_speed -= degress;
  return m_n_rotat_speed;
})

#undef USE_DECORATOR //ARGS这些名称比较常见,防止冲突所以禁用,自定义的宏最好用完就禁用,养成好习惯

int main(int , char *[])
{
    CCar car;
    car.oilfeed(45);
    car.brake(1000);
    return 0;
}


各位如果觉得有用,请把 “有用” 打到评论区🤪

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

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

相关文章

华为云1核2G免费使用一年

个人用户专享云服务器、云数据库产品每天上午9:30开抢&#xff0c;其他产品每天0点开放领取&#xff0c;企业用户所有产品每天0点开放领取&#xff1b; 云产品体验名额有限&#xff0c;领完即止。详情&#xff1a;https://www.vpspick.com/vps/591.html 通用入门型 T6 云服务…

数码管与译码器

目录 数码管 显示的基本原理 LED数码管的显示方式 静态显示方式 动态显示方式 具体案例 数码管静态显示 电路图 keil文件 数码管动态显示 电路图 keil文件 74LS138译码器 简介 译码表 译码器案例 电路图 keil文件 74HC595译码器 前言 举例解释 简单案例 …

手写防抖节流、手写深拷贝、事件总线

一、防抖 手写防抖--基本实现&#xff08;面试&#xff09; 手写防抖并且绑定this和event 添加取消功能 添加立即执行状态&#xff0c;默认不立即执行 underscore库介绍&#xff0c;lodash更轻量级 二、节流 用underscore库&#xff0c;调用throttle函数 手写基础版节流-&#…

《价值》-张磊-高瓴资本-4(上)-价值投资需要研究驱动,而非拍脑袋

第四章 价值投资方法与哲学&#xff08;上&#xff09; 在我的书架上&#xff0c;有一套书最为醒目&#xff0c;我总会在不经意间打开翻看&#xff0c;那就是由本杰明 格雷厄姆&#xff08;Benjamin Graham &#xff09;与戴维 多德&#xff08;David Dodd &#xff09;在 19…

【HTML】制作一个简单的三角形动态图形

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段HTML和CSS代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文件名改为[index.html]&#xff0c;CSS的文件名…

实用技巧:如何取消app的截屏禁用

因为我想要在小鹅通App做笔记,但是被小鹅通App禁用截屏了,这真是一个很糟糕的使用体验,虽然可能是为了保护商家权益…… 方法1 可以让商家设置课程可以截屏 方法2 手机root,安装Xposed框架,利用Xposed框架上面的插件我们可以对手机进行高度定制化,而安装Xposed框架的…

微信小程序 电影院售票选座票务系统5w7l6

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/Ssm/thinkphp/django/flask/express均支持 前端开发:vue.js 可选语言&#xff1a;pythonjavanode.jsphp均支持 运行软件…

4.5 day4 FreeRTOS

1.总结二进制信号量和计数型信号量的区别&#xff0c;以及他们的使用场景。 二进制信号量的数值只有0和1&#xff0c;用于共享资源的访问 计数型信号量的值一般是大于或者等于2&#xff0c;用于生产者和消费者模型 2.使用技术型信号量完成生产者和消费者模型实验。 3.总结Free…

基于单片机的炉温自动控制系统设计

**单片机设计介绍&#xff0c;基于单片机的炉温自动控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的炉温自动控制系统设计是一个综合性的项目&#xff0c;它结合了单片机技术、温度传感技术、控制算法以…

Redis从入门到精通(五)Redis实战(二)商户查询缓存

↑↑↑请在文章头部下载测试项目原代码↑↑↑ 文章目录 前言4.2 商户查询缓存4.2.1 缓存介绍4.2.2 查询商户信息的传统做法4.2.2.1 接口文档4.2.2.2 代码实现4.2.2.3 功能测试 4.2.3 查询商户信息添加Redis缓存4.2.3.1 逻辑分析4.2.3.2 代码实现4.2.3.3 功能测试 4.2.3 数据一致…

case语句

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 CASE 语句的执行方式与 IF...THEN...ELSIF 语句的执行方式类似&#xff0c;但是它是通过一个表达式的值来决定执行哪个分支 CASE 选择器表达式 WHEN 条件 1 THEN 语句序列 …

【00】【solidity最新教程】-简介

Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了 C&#xff0c;Python 和 Javascript 语言的影响&#xff0c;设计的目的是能在以太坊虚拟机&#xff08;EVM&#xff09;上运行。 Solidity 是静态类型语言&#xff0c;支持继承、库和复杂的用…

h5 笔记2

何谓cookiecookie是记录在浏览器里的变量&#xff0c;用来存放特定的信息&#xff0c;必须利用script程序或CGI程序来写入或读取。例如&#xff0c;有些网站为了让用户不必每次都重新输入账号&#xff0c;会利用cookie来记录账号&#xff0c;下次进入网页时就会自动弹出账号&am…

STM32CubeIDE基础学习-通用定时器中断实验

STM32CubeIDE基础学习-通用定时器中断实验 文章目录 STM32CubeIDE基础学习-通用定时器中断实验前言第1章 工程配置1.1 工程外设配置部分1.2 生成工程代码部分 第2章 代码编写第3章 实验现象总结 前言 生活中很多应用都有用到定时器功能、计时功能等。 定时器中断可以大大降低…

C语言基础(一)

C语言基础&#xff08;一&#xff09; 程序程序的设计步骤计算机中数据表示非数值数据数值转换&#xff08;二、八、十六&#xff09;进制转十进制十进制转换&#xff08;二、八、十六&#xff09;进制二进制和八、十六进制转换 基本数据类型关键字&#xff08;32个&#xff09…

【复习linux相关命令】

查看命令位置&#xff0c;查找命令 which命令 查看命令的位置 [rootVM-12-15-opencloudos ~]# which cd /usr/bin/cd [rootVM-12-15-opencloudos ~]# which java /usr/local/java/jdk1.8.0_261/bin/java [rootVM-12-15-opencloudos ~]# which pwd /usr/bin/pwdfind查找文件 …

【html威廉希尔体育体育羽毛球页面带注册】学生网页设计作业源码APP是不是真的?

Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 校园篮球网页设计 | 足球体育运动 | 体育游泳运动 | 兵乓球 | 网球 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a;结构CSS&#xff1a;样式 在操作方面…

Python人工智能应用----文本情感分析

1.问题引入 接着前两节课的内容&#xff0c;今天我们要构建一个人工智能系统。 它的目的是像人类一样&#xff0c;区分评价的情感是正面还是负面的。 接下来&#xff0c;我们要对提取的文本进行感情色彩的分析&#xff0c;这个就是文本情感分析&#xff0c;我们要使用机器学习…

Cisco路由器配置IPv6 Manual隧道

Cisco路由器配置IPv6 Manual隧道 IPv6与IPv4共存的方式 IPv6与IPv4共存方式大致有三种&#xff1a; 双栈&#xff1a;要求网络中所有设备均同时支持IPv4和IPv6转换&#xff1a;转换这种方式将IPv6协议的报头转换成IPv4协议报头。隧道&#xff1a;假定两个IPv6节点要使用IPv6…

6:算法基础--6.1:线性结构 ,6.2:查找算法

转上一节&#xff1a; http://t.csdnimg.cn/ql5Cdhttp://t.csdnimg.cn/ql5Cd 课程内容提要&#xff1a; 6&#xff1a;知识点考点详解 6.1&#xff1a;线性结构 通常分析时间复杂度的方法是从算法中选取-种对于所研究的问题来说是基本运算的操作&#xff0c;以 该操作重…