#在c++中定义一个特殊的运算符

#define a special operator in c++

本文关键字:一个 运算符 c++ 定义      更新时间:2023-10-16

说我想编一个特殊的运算符!+在C++中两个对象之间。我想使用!+,例如,因为我认为它比任何其他运算符都更有意义。

我可以做的一件基本的事情是找到一个免费的、未使用的运算符,并使用#define:进行替换

#define !+ %
class myclass 
{
  public:
   int operator %(myclass &c)
   {
      return 3;
   }
}

所以如果我以后写一些类似的东西

a!+b 

有了myclass的a和b实例,它就可以工作了。

现在,有没有什么方法可以定义它,用一个运算符,用一些函数?类似于:

#define a!+b -> a.operatorexclamativeplus(b)

这将使翻译不那么肮脏,并允许潜在的无限数量的这些新的"假操作员"!

"现在,有什么方法可以定义它,而不是用运算符,用一些函数?"

否,!+不构成预处理器宏的有效(正常)标识符。这些字符是为语言内部运算符保留的。

可用于宏定义的字符集是[_A-Za-z][_A-Za-z0-9]*regex语法1

根据c++标准定义草案部分

16预处理指令


控制行:

# define标识符替换列表新行
# define标识符lparen标识符列表选择)替换列表新行
# define标识符lparen…)替换列表新行
# define标识符lparen标识符列表,…)更换清单新品


更新:
我已经对此进行了一些实验,因为这实际上是一个有趣的问题,如果不是#define’d宏,我们可以为c++中的类使用重载内部运算符函数。

我发现实际上存在一些可能的(但可能很奇怪,而且行为出乎意料)选项,通过链接内在运算符并保持状态来重载它们的组合。对于新引入的运营商,你能得到的最接近的东西可能是:

class Foo {
    enum OpState { None , PlusState , NotState };   
public:
   Foo& operator+() {
       cout << "operator+()" << endl;
       opState = PlusState;
       return *this;
   }
   Foo& operator!() {
       cout << "operator!()" << endl;
       switch(opState) {
       case PlusState:
           operatorexclamativeplus();
           break;       
       default:
           opState = NotState;
           break;       
       }
       return *this;
   }    
private:
    Foo& operatorexclamativeplus() {
       cout << "operatorexclamativeplus()" << endl;
       opState = None;
       return *this;
    }
    Foo& operatorexclamativeplus(const Foo& rhs) {
       cout << "operatorexclamativeplus(const Foo& rhs)" << endl;
       opState = None;
       return *this;
    }   
    OpState opState;
};

int main() {
    Foo x;
    Foo z = !+x;
    return 0;
}

输出

operator+()
operator!()
operatorexclamativeplus()

参见活样本。


尽管,由于运算符优先级规则,这只适用于一元运算符(!的优先级高于二进制+),但您想要的形式似乎实际上无法实现:

class Foo {
    // ...
public:
    // Provide an additional binary 'operator+()'
    friend Foo& operator+(Foo& lhs, const Foo& rhs) {
        cout << "operator+(Foo& lhs, const Foo& rhs)" << endl;
        if(lhs.opState == NotState) {
            return lhs.operatorexclamativeplus(rhs);
        }
        return lhs;
    }
    // ...
};

int main() {
    Foo x;
    Foo y;
    Foo z = y !+ x;
    return 0;
}

看到这个悲惨的失败。


结论:

  1. 一些重载的内部运算符组合可能是语法上可能的,关于它们的优先定义,以及保持lvalues的状态
  2. 这可能不是一个很好的主意,试图超载内在运算符行为,引入了全新的语义

______________________________________________________________________________________

1)关于标识符的前导下划线(___),请阅读本答案中提到的标准部分,这些部分在语法上是有效的。

从技术上讲,C++不允许您定义新的运算符。但是,您可以从现有操作符中获得任何想要的行为,包括具有新操作符的外观
(不是说这是个好主意,只是回答了"有可能吗?")

你永远不能写a !+ b,因为!不是二进制运算符
但是你可以写a +! b,因为+是二进制的,而!是一元的
您可以重新定义这些运算符,以便a +! b返回您想要的内容。

诀窍是定义一元运算符以返回辅助对象,然后定义二元运算符以作用于该辅助对象。

作为一个例子,下面是将创建一个+的外观的代码!操作人员这个新+!操作员返回左手边加右手边的十倍。所以…1+!2将得到12。

class MyClass
{
public:
    int value;
};
class MyClassHelper
{
public:
    int value;
};
// define a unary ! operator that takes a right hand MyClass object
const MyClassHelper operator!(const MyClass right)
{
    // this operator just copies the value into a MyClassHelper object
    MyClassHelper answer;
    answer.value = right.value;
    return answer;
}
// define a binary + operator that takes a left hand MyClass object and a right hand MyClassHelper object
const MyClass operator+(const MyClass left, const MyClassHelper right)
{
    // this operator should return the value you want the +! operator to return
    MyClass answer;
    answer.value = left.value * 10 + right.value;
    return answer;
}
int main()
{
    // initialize a and b
    MyClass a, b;
    a.value = 1;
    b.value = 2;
    // this line will now compile with the +! operator
    MyClass c;
    c = a +! b;
    cout << "c = " << c.value << endl;
    return 0;
}

您不能在C/C++中定义新的运算符。标准不允许这样做,宏和模板的元编程功能也不足以绕过它

但这阻止了Brad Cox(Objecte-C)和Bjorne Stroustrup(C++/cfront)吗?当然不是!Bertrand Meyer也做到了(Eiffel),Kernighan和Plauger(RATFOR)也做到了。

在C/C++中添加新语言功能(如新运算符)的方法是创建自己的预处理器。您可以使用宏处理语言或编写自己的编译器,以便输入:

if (something) {
  a!+b
}

翻译成:

if (something) {
  a.operatorexclamativeplus(b);
}

C++编译器非常高兴。

你永远不会知道,你的新语言甚至可能会流行起来。有时确实如此。

在C++中不可能定义自己的唯一运算符。

我也认为在其他语言中也可以这样做。

其他人解释了这是不可能的。然而,你也问过如何将其作为一个函数,是的,这是"我首先要做的"。你只需将你想要的任何操作放入一个(自由/未绑定)函数中,给它一个合适的名称,这不会给读者带来任何困惑。

现在,如果你认为你的特殊情况足够特殊,足以违反规则,那么你可以做以下事情:

int x = 23 /strangeop/ 42;

这里,strangeop实际上是一个对象,并且对于这种类型的对象和整数存在重载的/运算符。第一个这样的运算符计算为一个代理对象,该代理对象保留对整数操作数的引用,但也定义了重载的/运算符,在该运算符中它接收另一个操作数,然后返回奇异运算的实际结果。请注意,您可以在这里使用任何二进制运算符,这更多是个人选择的问题。

注:

  • 您可以通过#define STRANGEOP /strangeop/进一步了解这一点
  • 使用它,您还可以定义一元奇异运算符,不过您仍然需要一个二进制运算符来重载
  • 将其与strange_op(23, 43)进行比较,并考虑其更好的可读性
  • 我还没有找到一个真正需要这种技术的案例,所以我不能告诉你它是否有效,以及它的实际限制在哪里