• C++ 自定义新的运算符


    在C++中,我们可以对已有运算符进行重载,但是我们却不能新增加运算符~
    可是,我们可以通过已有运算符和运算符重载来达到假装添加新的运算符的效果。

    效果展示

    std::cout << (a <add> b) << "\n"
              << (a <sub> b) << "\n"
              << (a <mlt> b) << "\n"
              << (a <div> b) << "\n";
    
    • 1
    • 2
    • 3
    • 4

    我们现在要实现这样的效果,嗯,就类似于 以尖括号括起来的就是我们的运算符。

    如何实现这种操作呢?

    其实是通过重载 大于小于号来完成的

    把原来的算式拆开就是:

    (lsh < oper) > rsh

    就是说,其实是通过一种取巧的方式来达到这一目的的。

    如何实现呢?

    • 重载 operator < 运算符,讲函数和左操作存储为中间变量
    • 重载 operator > 运算符,利用中间变量和右操作符进行计算

    为了保持复用,可以写一个类来保存中间变量

    template <typename ret> struct Operator;
    template <typename ret, typename A, typename B> struct Operator<ret(A, B)> {
      A lhs;
      using func_type = std::function<ret(A, B)>;
      func_type func;
      Operator(func_type &&fun) : func(fun) {}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    将函数绑定到类上面来,这里用了和std::function一样的技巧(特化),把返回值和参数类型确定

    现在就创建好了一个 Oper 运算子

    然后,重载 operator <

    将左操作数存入算子对象中

    template <typename ret, typename A, typename B>
    Operator<ret(A, B)> operator<(A /*copy*/ a, Operator<ret(A, B)> &now) {
      now.lhs = a; // 可优化,有拷贝
      return now;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后,重载 operator >

    计算左操作数和右操作数的结果

    template <typename ret, typename A, typename B>
    ret operator>(const Operator<ret(A, B)> &now, B /*copy*/ b) {
      return now.func(now.lhs, b);
    }
    
    • 1
    • 2
    • 3
    • 4

    现在就可以简单的使用其进行算子定义了!

    比如:

    Operator<double(double, double)> maxs{
        [](double a, double b) -> double { return std::max(a, b); }};
    
    • 1
    • 2

    然后就可以使用 a b 这种形式来运算了

    其实如果不介意使用宏的话,可以让其变得更加的 简洁

    #define operator_register(name, ret, oper1, oper2, body)                       \
      Operator<ret(oper1, oper2)> name body;
    
    #define add <o_add>
    #define sub <o_sub>
    #define mlt <o_mlt>
    #define div <o_div>
    operator_register(o_add, int, int, int,
                    {[](int a, int b) -> int { return a + b; }});
    operator_register(o_sub, int, int, int,
                    {[](int a, int b) -> int { return a - b; }});
    operator_register(o_mlt, int, int, int,
                    {[](int a, int b) -> int { return a * b; }});
    operator_register(o_div, int, int, int,
                    {[](int a, int b) -> int { return a / b; }});
    int main() {
      int a = 1, b = 1;
    
      
      std::cout << (a add b) << "\n"
                << (a sub b) << "\n"
                << (a mlt b) << "\n"
                << (a div b) << "\n";
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    当然,可以实现得更加复杂,支持运算符优先级,这是后话

    现在的代码,嗯,怎么看怎么有点不想C++

    std::cout << (a add b add 2 add 3) << "\n"
              << (a add b add 2 add 3 sub 4) << "\n";
    
    • 1
    • 2

    {amjieker}

  • 相关阅读:
    【附源码】计算机毕业设计JAVA传统文化知识竞赛系统
    conan 入门指南
    Python数据挖掘:入门、进阶与实用案例分析——自动售货机销售数据分析与应用
    Java面试必考题之线程的生命周期,结合源码,透彻讲解!
    面试突击61:说一下MySQL事务隔离级别?
    Config配置文件读写
    web网页设计期末课程大作业:漫画网站设计——我的英雄(5页)学生个人单页面网页作业 学生网页设计成品 静态HTML网页单页制作
    软链接、硬链接的本质与区别
    【算法题】8029. 与车相交的点
    牛客C++刷题记录
  • 原文地址:https://blog.csdn.net/qq_51986723/article/details/127569267