代码之家  ›  专栏  ›  技术社区  ›  AlwaysLearning

除了I/O之外,重载移位运算符是一个好的设计吗?

  •  5
  • AlwaysLearning  · 技术社区  · 10 年前

    我正在为A*搜索算法实现开放列表(OL)类。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类通过重载移位运算符来支持类似的表示法有意义吗

      OL ol;
      ...  
      OL << successorNode;
      ... 
      OL >> curNode;
      
    2. (只有当对1.的回答为“是”时)我才能尽可能支持这一点(即 cout cin 对于内置类型):

      OL ol;
      ...
      successorNode >> OL;
      ...
      curNode << OL;
      
    3. (仅当对1.的回答为“是”时)轮班操作员的这种用法是否适用于标准集装箱:

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

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

    • 询问所提出的设计是否违背了重载运算符应模仿这些运算符对于内置/标准类型的含义的原则。

    • 询问为什么不使用shift运算符来减少标准容器的冗长使用。

    2 回复  |  直到 10 年前
        1
  •  6
  •   Community Mohan Dere    5 年前

    您的问题的答案可能高度基于个人意见,因为没有硬性规定允许/禁止使用运算符重载。因此,我将提出一些论点,帮助你决定这是不是一个好主意,而不是一个艰难的答案。

    关于您的 前两个问题 :

    最小惊奇原则 。如果有人看到你的代码,他会想到什么?这是什么意思,或者,作为相反的极端,他会期待完全不同的东西吗?是否超载 值得的 如果适用的话?例如,在学习了操作员的操作之后,它是否会使代码更清晰?如果利大于弊,那就去吧!否则,不要。

    作为这一点的一个侧面节点,我甚至遇到了这样一个论点,即iostream运算符是运算符重载的一个坏例子,因为它们不会移位整数。然而,我倾向于不同意,并将此视为个人意见的问题。

    适用于您当前的情况:用户是否希望通过呼叫操作员获得其他结果?E、 g.他可能会从队列中得到另一个结果吗?如果是,不要超载。或者用户是否应该熟悉伪代码表示法,并看到其相似性?如果是这样的话,就要超载!

    关于 第三个问题 :

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

    QList<int> list;
    list<<5;
    

    摘要:

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

    注意:只有在没有禁止使用运算符重载的样式指南时,所有这些才适用!

        2
  •  2
  •   Arne Vogel    10 年前

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

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

    还有另一个宏可以促进这种使用,并记录进入和退出,但您可以理解。虽然我还没有将其用于容器或容器适配器,但我想这对于“类似流”的容器/适配器、特别是FIFO队列、优先级队列甚至堆栈来说都是有意义的。Qt的用法有点难以接受,因为您必须猜测新项目是添加在列表的前面还是后面。我假设它是背面的,文档证实了这一点,所以这并不太令人惊讶。但是,他们没有 operator >> 这很有道理,因为我不知道它会从列表的哪一端弹出该项目。这对问题1是肯定的,对问题3是“有点”的。

    现在,对于第二个问题,我强烈建议不要这样做。为什么?虽然对称性看起来很好,但对于 <iostream> ,即使我们无视这一点,它也会打开一个蠕虫罐头:

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

    真正地即使我们同意语法是适当的,一个不经意的读者现在也可能需要检查这些运算符是左关联还是右关联,以便了解哪个项目首先进入队列(对于优先级队列来说,这显然无关紧要)。但以下情况更糟。假设您有以下代码:

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

    但后来有人决定,他更倾向于将价值观放在前面,并将其改写为:

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

    Sanity现在终于离开了我们,这将向队列中推送一个值(6),因为它的求值为 (50 >> 3) >> q (具有整数位移位,导致值6)。我认为这也是为什么这种用法从未被考虑,或者可能被考虑但被驳回的一个有力原因,因为 <iostream> .