【问题标题】:Custom key in std::map, overloading < operatorstd::map 中的自定义键,重载 < 运算符
【发布时间】:2016-06-28 17:27:41
【问题描述】:

在为map 中的自定义键重载operator&lt; 时,为什么参数和函数类型都需要const

【问题讨论】:

  • 常量引用意味着没有额外的参数副本,您不能在比较函数中意外更改它们
  • 你想比较两个 const 键,你需要两个 const,每个参数一个。
  • 函数后面的const表示函数不会修改正在进行比较的对象
  • @chema989 不太确定。这并不能真正解释为什么需要const

标签: c++ dictionary operator-overloading


【解决方案1】:

std::map&lt;K, V&gt; 的 value_type 不是您可能认为的 std::pair&lt;K, V&gt;,但实际上是 std::pair&lt;const K, V&gt;因此,对键调用的任何比较都处理 const 对象。

现在当编译器看到

a < b

并且ab 中的至少一个是用户定义的类型,编译器会调用其中一个

operator < (a, b); //(1)

a.operator < (b); //(2)

(如果这两个都可用,则会发出错误)。

非常量成员函数(包括任何运算符)只能在非常量对象上调用。因此,因为a 是常量,所以在//2 的情况下,需要将函数声明为常量。由于b 也是常量,所以参数必须是常量引用,因为非常量引用不能绑定到常量对象。因此对这两个 const 都有要求。

该参数除了是 const 之外还有另一个选项。它可以按值获取参数,但这意味着不必要的复制。同样,如果您选择声明非成员 operator &lt;,则应通过 const 引用(推荐)或按值获取这两个参数。

【讨论】:

    【解决方案2】:

    算子的原型

    bool operator<(const Element& b) const { ..... }
    

    const Element&amp; b 表示在调用 operator&lt; 时不会创建元素 b 的额外副本,并且不会在方法内部修改参数。第二个const 表示调用operator&lt; 的对象在此调用调用时不会被修改。

    【讨论】:

    • 第二个const 只是承诺进行比较的对象不会被修改
    • operator&lt; 有两个原型,一个是非成员原型,一个是成员原型。更常用和推荐的一种是非成员(原因太长,无法进入这里),但您已将成员原型称为“the”原型。
    【解决方案3】:

    据我了解,const reference 用于参数类型有两个目的:

    1. 从它的签名中可以看出,参数在函数体内是不可修改的,任何此类冒险都会导致编译器错误。
    2. key 类型没有额外不必要的复制。

    将成员函数设为const,这样您仍然可以执行find(或任何其他纯阅读(除非修改mutable 成员)操作)调用const 地图对象。如果没有该 const,尝试在 const map 对象上调用这些成员函数时,会导致编译错误。

    当您尝试创建自定义比较函数时,不需要用于全局或非成员函数的 const

    bool operator<(const Key& a, const Key& b) /* no const required here*/ {....}
    

    函数的const 仅适用于成员函数,因为它使this 指针或实例成为const,而这不适用于全局或非成员比较运算符

    【讨论】:

      【解决方案4】:

      参数中的常量是函数承诺其调用者不修改传入的参数。当通过引用传递参数时通常需要它以避免额外的副本但不会被修改,例如:

      void function(const Type& var) 
      {
          // can't modify var here, but can read and call its const methods (see below)
      }
      

      方法声明中的常量是承诺不修改被调用对象的内部状态的方法。例如

      void Class::function(const Type& var) const 
      {
         // can't modify var here
         // can't modify "this" here (call other non const methods or change member variables)
      }
      

      这些承诺可以通过抛弃 constness 来打破(毕竟这是我们正在谈论的 C++),但无论如何这就是意图。

      总是要求尽可能少是个好主意。如果方法不改变对象——将其声明为 const,那么您可以在该类的 const 实例上调用此方法(例如,当它作为 const 引用传递到其他地方时)。

      在 std::map 上自定义 operator &lt; 的情况下,您不能在参数中使用非常量引用的原因是 std::map 将在其自己的一个或多个方法中调用您的运算符,并且它们可能自己声明为 const 。编译器不允许将 const 对象传递给不承诺不修改它的函数。

      你不能声明 operator &lt; 本身非 const 的原因(假设它不是一个独立的函数,而是你的自定义类的一个方法用作键)是相同的——std::map 已经承诺不修改密钥(这会对一个排序造成严重破坏),因此它不能调用任何不保证相同的方法。

      自定义operator &lt;在用于容器内分类时还有其他要求——它必须满足LessThanComparable的概念。

      【讨论】:

        猜你喜欢
        • 2017-08-20
        • 2023-03-21
        • 2014-07-15
        • 1970-01-01
        • 2022-01-21
        • 2014-07-24
        • 2013-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多