为 I/O 以外的事物重载移位运算符是否是一个好的设计?

Can overloading shift operators for things other than I/O be a good design?

我正在为 A* 搜索算法实施开放列表 (OL) class。 OL 基本上是搜索节点的专用优先级队列。在描述 A* 算法的伪代码中经常看到这样的符号:

    successorNode -> OL // put the successor node into OL
    ...
    curNode <- OL // get the best node from OL and store it in curNode

三个问题:

  1. 我的 OL class 通过重载移位运算符来支持类似的符号是否有意义:

    OL ol;
    ...  
    OL << successorNode;
    ... 
    OL >> curNode;
    
  2. (仅当 1. 的答案为 "Yes" 时)我能否支持这个(即 cout 和 [=16 不支持的用法) =] 对于内置类型):

    OL ol;
    ...
    successorNode >> OL;
    ...
    curNode << OL;
    
  3. (仅当 1. 的答案为 "Yes" 时)移位运算符的这种用法对标准容器是否有意义:

    vector<int> v;
    v << 5; // instead of v.push_back(5)
    

编辑:这个问题的目的有两个:

您问题的答案很可能主要基于个人意见,因为没有硬性规定 allow/disallow 这种运算符重载的用法。因此,我将提出一些论据来帮助您决定这是否是一个好主意,而不是硬性回答。

关于你的前两个问题

最小惊奇原则的角度考虑一下。如果有人看到你的代码,他会期待什么?会立即清楚这是什么意思,或者,作为相反的极端,他(她)会期待完全不同的东西吗?如果适用,重载 值得 惊喜吗?比如,了解了operators是干什么的,是不是让代码更清晰?如果利大于弊,那就去吧!否则不要。

作为这一点的侧节点,我什至遇到了这样的论点,即 iostream 运算符是运算符重载的一个坏例子,因为它们不移动整数。但是,我倾向于不同意,并将其视为个人意见。

应用于您当前的情况:用户可能希望通过呼叫接线员获得其他结果吗?例如。他可能会期待队列中的另一个结果吗?如果是这样,请不要超载。还是希望用户熟悉伪代码符号,并看到相似之处?如果是这样,请超载!

关于第三个问题

有人同意,有人不同意。例如,Qt 框架的容器支持这种用法:

QList<int> list;
list<<5;

总结:

答案取决于它是否使您的代码更具可读性(当然还有个人意见)。

注意:所有这些仅适用于没有风格指南或禁止使用运算符重载的情况!

这是一个风格问题,所以这是我的 2 美分:我喜欢重载这些运算符,这有助于获得简洁明了的语法,并且用法与 <iostream> 一致。例如:

void MyLoggableClass::foo(int i)
{
    LOG_TRACE("foo(" << i << ") called");
}

还有另一个宏可以促进这种用法并记录进入和退出,但你明白了。虽然我没有将它用于容器或容器适配器,但我想它对 "stream-like" containers/adapters 很有意义,尤其是 FIFO 队列、优先级队列甚至堆栈。 Qt 的用法有点难以接受,因为你必须猜测新项是添加在列表的前面还是后面。我假设它是背面,文档证实了这一点,所以这并不奇怪。但是,它们没有 operator >> 并且这是有道理的,因为我不知道它会从列表的哪一端弹出该项目。问题 1 是肯定的,问题 3 是 "somewhat"。

关于第二个问题,我强烈建议不要这样做。为什么?虽然对称性看起来不错,但它对 <iostream> 的用户来说更令人惊讶,即使我们忽略这一点,它也会打开一罐蠕虫:

queue<item> q;
item1 >> q << item2;

真的吗?即使我们同意语法是合适的,一个偶然的 reader 现在可能不得不查找这些运算符是左结合还是右结合,只是为了了解哪个项目首先进入队列(对于优先级排队当然会更重要)。但下面的情况更糟。假设您有以下代码:

queue<int> q;
q << 3 << 50;

但后来有人决定他更喜欢预先设置值并将其重写为:

queue<int> q;
50 >> 3 >> q;

Sanity 现在终于离开了我们——这会将单个值 (6) 推入队列,因为它被评估为 (50 >> 3) >> q(具有整数位移位,结果为值 6)。我认为这也是为什么 <iostream>.

从未考虑过这种用法,或者可能考虑过但被驳回的一个重要原因。