是否有可能在C ++中重载运算符关联性?

时间:2014-01-30 00:35:41

标签: c++ operator-overloading associative

我正在构建一个稍微不对称的类。在投诉出现之前,它必然是不对称的。当两个对象一起添加时,必须发生转换(需要花费一些时间的操作),并且转换最自然地发生在正确的加数上。

为了使这个具体,这是一个正在发生的事情的通用例子......

class Foo {
    char _fav;
    int _prop;

public:
    const char fav() const {return _fav;}
    const int prop() const (return _prop;}
    void changeFav(char); // complicated method that also changes _prop
    void changeProp(int); // straightforward method
}

Foo
operator + (Foo A, Foo B) {
    Foo sum;
    if (A.fav() != B.fav()) A.changeFav(B.fav);
    sum.changeProp(A.prop() + B.prop());   
    return sum;
}

为了添加两个Foo,它们需要具有相同的_fav,因此必须选择要转换的内容。根据{{​​1}}的详细信息,最自然地更改左加数以匹配正确的加数。

然而,在做的时候:

Foo

如果Foo A,B,C; Foo D = A + B + C; // D = (A + B) + C Foo E = A + (B + C); 已经与A具有相同的_fav,那么C会调用changeFav两次(一次将D更改为A._fav B._fav然后再次将(A+B)._fav更改为C._fav),将E更改为B._fav更改为C._fav。我更喜欢后者,但希望避免强迫用户使用括号进行多次添加。

有没有办法重载operator +的关联性以实现这一目标?

4 个答案:

答案 0 :(得分:3)

你可以做一个黑客攻击。您必须使用其他类型来保存操作的中间结果,然后您可以使用隐式转换来评估结果。以下是如何在C ++中实现Python样式比较运算符的示例:

#include <vector>
#include <cstdio>

struct S {
    S(int x) : val(x) { }
    int val;
};

struct Comparison {
    std::vector<S> operands;
    explicit Comparison(S x)
    {
        operands.push_back(x);
    }
    operator S()
    {
        auto i = operands.begin(), e = operands.end();
        S prev = *i;
        for (i++; i != e; i++) {
            S cur = *i;
            if (prev.val >= cur.val)
                return S(0);
            prev = cur;
        }
        return S(1);
    }
    void append(const Comparison &a)
    {
        operands.insert(
            operands.end(),
            a.operands.begin(),
            a.operands.end());
    }
    void append(const S &a)
    {
        operands.push_back(a);
    }
};

Comparison operator<(const Comparison &left, const Comparison &right)
{ Comparison result(left); result.append(right); return result; }
Comparison operator<(const Comparison &left, const S &right)
{ Comparison result(left); result.append(right); return result; }
Comparison operator<(const S &left, const Comparison &right)
{ Comparison result(left); result.append(right); return result; }
Comparison operator<(const S &left, const S &right)
{ Comparison result(left); result.append(right); return result; }

int main()
{
    S x(0);
    x = S(0) < S(1) < S(2) < S(3);
    std::printf("0 < 1 < 2 < 3 = %d\n", x.val);
    x = S(0) < S(1) < S(3) < S(2);
    std::printf("0 < 1 < 3 < 2 = %d\n", x.val);
    return 0;
}

但是,在这种情况下,我会迅速抛弃+运算符。我会避免将+用于任何非关联和可交换的操作,因为这是数学中+的约定。相反,您可以使用可变参数函数(使用模板)来执行所需的计算。

答案 1 :(得分:3)

有点,但你不会喜欢&#34;怎么&#34;它的。

首先,您需要阅读并理解Boost.Proto文档。然后,您需要弄清楚如何转换所有表达式树以反转操作的顺序。然后,您需要对最终用户透明地表达树的评估。可能在转让?我对Proto没有多少讨论,但与this article on Proto-based optimizations类似的东西可能是一个有用的起点。

答案 2 :(得分:2)

没有。那么为什么不改变右手操作数的优惠呢?

答案 3 :(得分:2)

来自c ++标准第5条,

  

重载运算符遵循第5章中指定的语法规则。

Where子句5指定运算符优先级和关联性。