【问题标题】:C++ strict weak ordering derived classC++ 严格弱排序派生类
【发布时间】:2015-09-20 07:51:34
【问题描述】:

我正在尝试在要放置在 STL 集容器中的子类中实现严格的弱排序。 STL 集使用 operatorlive demo,显示了我不确定的地方。我正在使用易于使用的 std::tie technique 对字段进行排序。我不确定的领域是在对派生字段调用 std::tie 比较之前,我应该如何调用超类的运算符

struct Base {
    Base(const int& rIntVal,  const std::string& rStrVal)
        : mIntVal(rIntVal)
        , mStrVal(rStrVal)
    {}
    inline bool operator<(const Base& rhs) const {
        return std::tie(mIntVal, mStrVal) < std::tie(rhs.mIntVal, rhs.mStrVal);
    }
private:    
    int mIntVal;
    std::string mStrVal;
};

struct Derived : public Base {
    Derived(
        const int& rIntVal, 
        const std::string& rStrVal, 
        const std::string& rOtherStrVal,
        const std::string& rOtherStrVal1)
        : Base(rIntVal, rStrVal)
        , mOtherStrVal(rOtherStrVal)
        , mOtherStrVal1(rOtherStrVal1)
    {}
    inline bool operator<(const Derived& rhs) const {
        // not sure what to do here - this is my best guess???
        if( Base::operator<(rhs) ) {
            return std::tie(mOtherStrVal, mOtherStrVal1) < 
                std::tie(rhs.mOtherStrVal, rhs.mOtherStrVal1);
        } else {
            return false;
        }
    }
private:    
    std::string mOtherStrVal;
    std::string mOtherStrVal1;
};

【问题讨论】:

    标签: c++ c++11 stl tuples unordered-set


    【解决方案1】:

    首先,您可以选择让派生字段优先于基础字段,以便首先考虑派生成员,或者您可以优先考虑基础字段。做什么取决于你的类的含义以及它应该如何排序。

    您已选择先比较基本字段,这很好,所以我们将继续这样做。

    要成为严格的弱排序,您应该仅在基本子对象相等时比较派生字段(即,两者都不小于另一个)。

    使用当前代码,如果您有 lhs.mIntVal &lt; rhs.mIntVal,您应该返回 true,但是您继续比较派生字段,最终可能会说 lhs 小于 @ 987654325@ 即使基类的结果表明是这样。

    因此,要使结果正确,您需要等效于:

    bool operator<(const Derived& rhs) const {
        if (Base::operator<(rhs))
          return true;
        else if (rhs.Base::operator<(*this))
          return false;
        // base parts are equivalent, compare derived parts:
        return std::tie(mOtherStrVal, mOtherStrVal1) < 
               std::tie(rhs.mOtherStrVal, rhs.mOtherStrVal1);
    }
    

    这在逻辑上是正确的,但不是最理想的,因为您调用了两次Base::operator&lt;。您可以通过在 tie 表达式中包含基础对象来避免这种情况,如 ecatmur 所示。

    【讨论】:

    • 这是否等同于以下 ecatmur 的答案?
    • 它会给出相同的答案,但在某些情况下比 ecatmur 的效率低。我的回答详细解释了这个问题,但 ecatmur 的回答给出了该问题的最佳解决方案。
    • 很好的答案,顺便说一句,我忘了问 - 在您的示例中,如何在不对基础执行静态案例的情况下编译 'rhs.Base::operator
    • @Johanthan Wakely - 我这里有一个不太编译的例子:coliru.stacked-crooked.com/a/a58b44078ffb6d12
    • @johnco3,因为你的大括号弄错了,你在operator&lt; 的最后一个else 之后缺少了一个{。获取一个允许您检查大括号是否匹配的编辑器,并且它变得很明显。在我的回答中,lhs 也应该是*this(现已修复)。 coliru.stacked-crooked.com/a/44dcf43b9a7cae88
    【解决方案2】:

    您最好将引用绑定到基类:

    bool operator<(const Derived& rhs) const {
        return std::tie(static_cast<const Base&>(*this), mOtherStrVal, mOtherStrVal1) < 
            std::tie(static_cast<const Base&>(rhs), rhs.mOtherStrVal, rhs.mOtherStrVal1);
    }
    

    这将首先按超类字段进行比较,然后按子类字段进行比较。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-14
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      • 2016-02-04
      • 2019-06-09
      • 1970-01-01
      • 2010-11-02
      相关资源
      最近更新 更多