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

等有时间了我再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 <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;
}


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

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-06 02:56:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-06 02:56:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-06 02:56:03       87 阅读
  4. Python语言-面向对象

    2024-04-06 02:56:03       96 阅读

热门阅读

  1. deepspeed学习-多机all_reduce

    2024-04-06 02:56:03       31 阅读
  2. Kubernetes学习笔记6

    2024-04-06 02:56:03       41 阅读
  3. 威胁建模与网络安全测试方法

    2024-04-06 02:56:03       42 阅读
  4. 2024.3.24力扣每日一题——零钱兑换

    2024-04-06 02:56:03       35 阅读
  5. 2024/4/2 HarmonyOS学习笔记一TS数据类型

    2024-04-06 02:56:03       36 阅读
  6. matlab学习(二)(4.2-4.8)

    2024-04-06 02:56:03       32 阅读
  7. 【趣味学算法】11_黑洞数

    2024-04-06 02:56:03       36 阅读
  8. postcss安装和使用

    2024-04-06 02:56:03       40 阅读
  9. 【WPF应用26】C#中的CheckBox控件详解与应用示例

    2024-04-06 02:56:03       43 阅读
  10. 热浪

    2024-04-06 02:56:03       30 阅读