C++ 严格弱排序派生 class
C++ strict weak ordering derived class
我正在尝试在我想放置在 STL 集容器中的子类中实施严格的弱排序。 STL 集使用 operator< 以严格的弱顺序对其元素进行排序。在我的例子中,我有一个类型层次结构,我不太确定如何为派生类型实现这一点。为此,我快速整理了一下live demo showing where I am uncertain. I am ordering the fields using an easy to use 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;
};
首先,您可以选择让派生字段优先于基字段,以便首先考虑派生成员,或者您可以让基字段优先。要做什么取决于你的 class 的含义以及它应该如何排序。
您选择了先比较基字段,这很好,所以我们就这样做。
要成为严格的弱排序,您应该只在基本子对象等效时比较派生字段(即两者都不小于另一个)。
使用当前代码,如果您有 lhs.mIntVal < rhs.mIntVal
,您应该 return 为真,但是您继续比较派生字段,最终可能会说 lhs
是 不小于rhs
,即使基础class的结果说是。
因此,为了使结果正确,您需要等同于:
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<
两次。如 ecatmur 所示,您可以通过在 tie 表达式中包含基础对象来避免这种情况。
您最好将引用绑定到基数 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);
}
这将首先通过 superclass 字段进行比较,然后通过 subclass 字段进行比较。
我正在尝试在我想放置在 STL 集容器中的子类中实施严格的弱排序。 STL 集使用 operator< 以严格的弱顺序对其元素进行排序。在我的例子中,我有一个类型层次结构,我不太确定如何为派生类型实现这一点。为此,我快速整理了一下live demo showing where I am uncertain. I am ordering the fields using an easy to use 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;
};
首先,您可以选择让派生字段优先于基字段,以便首先考虑派生成员,或者您可以让基字段优先。要做什么取决于你的 class 的含义以及它应该如何排序。
您选择了先比较基字段,这很好,所以我们就这样做。
要成为严格的弱排序,您应该只在基本子对象等效时比较派生字段(即两者都不小于另一个)。
使用当前代码,如果您有 lhs.mIntVal < rhs.mIntVal
,您应该 return 为真,但是您继续比较派生字段,最终可能会说 lhs
是 不小于rhs
,即使基础class的结果说是。
因此,为了使结果正确,您需要等同于:
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<
两次。如 ecatmur 所示,您可以通过在 tie 表达式中包含基础对象来避免这种情况。
您最好将引用绑定到基数 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);
}
这将首先通过 superclass 字段进行比较,然后通过 subclass 字段进行比较。