C ++严格弱排序派生类

时间:2021-09-13 00:34:24

I'm trying to implement strict weak ordering in a subclass that I want to place in an STL set container. The STL set uses operator< to order its elements in strict weak ordering. In my case I have a hierarchy of types and I am not quite sure how to achieve this for derived types. To this end, I put together a quick live demo showing where I am uncertain. I am ordering the fields using an easy to use std::tie technique. My area of uncertainty is how I should call the superclass' operator< prior to calling the std::tie comparison on the derived fields.

我正在尝试在我想要放置在STL集合容器中的子类中实现严格的弱排序。 STL集使用operator <以严格的弱顺序对其元素进行排序。在我的情况下,我有一个类型的层次结构,我不太确定如何为派生类型实现这一点。为此,我整理了一个快速现场演示,展示了我不确定的地方。我使用易于使用的std :: tie技术来命令字段。我不确定的领域是如何在派生字段上调用std tie比较之前调用超类'operator <。< p>

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;
};

2 个解决方案

#1


2  

Firstly, you could choose to have the derived fields take priority over the base ones, so that the derived members are considered first, or you could give the base fields priority. Which to do depends on the meaning of your class and how it should be sorted.

首先,您可以选择使派生字段优先于基础字段,以便首先考虑派生成员,或者可以为基本字段赋予优先级。要做什么取决于您的类的含义以及如何对其进行排序。

You have chosen to compare the base fields first, which is fine, so we'll go with that.

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

To be a strict weak ordering you should only compare the derived fields when the base sub-objects are equivalent (i.e. neither is less-than the other).

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

With your current code if you have lhs.mIntVal < rhs.mIntVal you should return true, but instead you go on to compare the derived fields, and might end up saying that lhs is not less than rhs even though the the result from the base class says it is.

使用当前代码,如果你有lhs.mIntVal 你应该返回true,而是你继续比较派生字段,并且最终可能会说lhs不小于rhs,即使是来自base的结果班级说它是。

So to make the result correct you need something equivalent to:

所以为了使结果正确,你需要一些相当于:

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);
}

This is logically correct, but sub-optimal because you call Base::operator< twice. You could avoid that by including the base objects in the tie expression as ecatmur shows.

这在逻辑上是正确的,但是次优,因为你调用Base :: operator <两次。您可以通过在ecatmur显示的tie表达式中包含基础对象来避免这种情况。< p>

#2


4  

You would do best to tie a reference to the base class:

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

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);
}

This will compare by the superclass fields first and then by the subclass fields.

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

#1


2  

Firstly, you could choose to have the derived fields take priority over the base ones, so that the derived members are considered first, or you could give the base fields priority. Which to do depends on the meaning of your class and how it should be sorted.

首先,您可以选择使派生字段优先于基础字段,以便首先考虑派生成员,或者可以为基本字段赋予优先级。要做什么取决于您的类的含义以及如何对其进行排序。

You have chosen to compare the base fields first, which is fine, so we'll go with that.

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

To be a strict weak ordering you should only compare the derived fields when the base sub-objects are equivalent (i.e. neither is less-than the other).

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

With your current code if you have lhs.mIntVal < rhs.mIntVal you should return true, but instead you go on to compare the derived fields, and might end up saying that lhs is not less than rhs even though the the result from the base class says it is.

使用当前代码,如果你有lhs.mIntVal 你应该返回true,而是你继续比较派生字段,并且最终可能会说lhs不小于rhs,即使是来自base的结果班级说它是。

So to make the result correct you need something equivalent to:

所以为了使结果正确,你需要一些相当于:

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);
}

This is logically correct, but sub-optimal because you call Base::operator< twice. You could avoid that by including the base objects in the tie expression as ecatmur shows.

这在逻辑上是正确的,但是次优,因为你调用Base :: operator <两次。您可以通过在ecatmur显示的tie表达式中包含基础对象来避免这种情况。< p>

#2


4  

You would do best to tie a reference to the base class:

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

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);
}

This will compare by the superclass fields first and then by the subclass fields.

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