#define c ++中的特殊运算符

时间:2014-09-22 21:51:36

标签: c++ operator-overloading operators c-preprocessor

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

我能做的一件基本事情就是找到一个免费的,未使用的操作符并使用#define进行替换:

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

所以如果我后来写了像

这样的东西
a!+b 

使用myclass的a和b实例,它会起作用。

现在,有没有办法定义它而不是运算符,具有一些功能?类似的东西:

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

这会使翻译变得更加脏,并且可以允许这些新的“虚假运营商”中有无限数量的翻译!

5 个答案:

答案 0 :(得分:10)

  

"现在,有没有办法定义它而不是运营商,有一些功能?"

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

可用于宏定义的字符集是[_A-Za-z][_A-Za-z0-9]* 正则表达式语法 1

来自c++ standards definitions 草案部分

  

16个预处理指令

     

...
  控制线:
  ...
  # define 标识符替换列表换行符   # define 标识符 lparen identifier-listopt)replacement-list new-line
  # define 标识符 lparen ...)replacement-list new-line
  # define 标识符 lparen identifier-list,...)replacement-list new-line


<强>更新
我已经尝试了一点,因为这实际上是一个有趣的问题,如果不是#define&#d; 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()

请参阅live sample


但是,由于operator precedence rules,这只适用于一元运算符(!的优先级高于二进制+),您想要的形式似乎没有实际上是可以实现的:

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;
}

See this miserably fail


<强>结论:

  1. 内部运算符的一些重载组合可能是 在语法上可能,关于它们的优先级定义,和 维持左值的状态
  2. 尝试超载内在可能不是一个好主意 操作员行为,引入全新的语义。
  3. <强> ______________________________________________________________________________________

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

答案 1 :(得分: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;
}

答案 2 :(得分:1)

您无法在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 ++编译器非常高兴。

你永远不会知道,你的新语言甚至可能会流行起来。有时它们会这样做。

答案 3 :(得分:0)

无法在C ++中定义自己的唯一运算符。

我还说其他语言可能会这样做。

答案 4 :(得分:0)

其他人解释了这种不可能性。但是,你也问过这个功能是什么,是的,那个&#39; s&#39;我先走的路。你只需将你想要的任何操作放入(自由/未绑定)函数中,给它一个合适的名称,这不会给读者造成任何混淆。

现在,如果您认为您的特殊情况足以打破规则,那么您可以执行以下操作:

int x = 23 /strangeop/ 42;

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

注意:

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