我有以下运算符<应该首先按值排序,然后按另一个值排序:
inline bool operator < (const obj& a, const obj& b)
{
if(a.field1< b.field1)
return true;
else
return a.field2 < b.field2;
}
我觉得这是不正确的,如果没有对成员变量进行另一次第三次比较测试,你就不能这样做,但我找不到任何不起作用的例子。 那么这真的和预期的一样吗? 感谢
编辑: 我会把它编码为:
inline bool operator < (const obj& a, const obj& b)
{
if(a.field1< b.field1)
return true;
else if(a.field1> b.field1)
return false;
else
return a.field2 < b.field2;
}
有什么不同吗?我问,因为我知道我的经验是正确的,但也比第一次更长
答案 0 :(得分:32)
如果Obj::field2
的值相等,则只应比较Obj::field1
的值。
/* This will meet the requirements of Strict-Weak-Ordering */
if (a.field1 != b.field1) return a.field1 < b.field1;
else return a.field2 < b.field2;
“正确的”实现方法仅使用operator<
来比较字段,下面看起来比实际情况复杂。
然而,它会产生与之前编写的易于理解的示例相同的结果。
return a.field1 < b.field1 || (
!(b.field1 < a.field1) && a.field2 < b.field2
);
operator<
而不会引起很多麻烦?您可以使用已经std::tuple
的 STL 中的operator<
来定义多个字段,例如以下示例。
#include <utility>
...
inline bool
operator< (Obj const& lhs, Obj const& rhs)
{
return std::tie (lhs.field1, lhs.field2) < std::tie (rhs.field1, rhs.field);
}
如果你的编译器还没有对C ++ 11的支持,你只需要比较每个对象的两个字段,你就可以使用std::pair
。
std::make_pair
的原因与上一个使用std::tie
的示例相同。
#include <utility>
...
inline bool
operator< (Obj const& lhs, Obj const& rhs)
{
return std::make_pair (lhs.field1, lhs.field2)
< std::make_pair (rhs.field1, rhs.field2);
}
使用std::pair
将需要创建成员的副本,这在某些情况下是不合需要的。
有关详细信息,请参阅以下问题/答案,但总结一下; c ++ 11方法不会产生太多开销,而且实现起来非常简单。
答案 1 :(得分:7)
想想如果a.field1
大于b.field1
但a.field2
小于b.field2
会发生什么。在这种情况下,您在field2
上比较基于的 ,这不是您想要的。
你只想让field2
在field1
字段相等的地方发挥作用,所以你要找的是(伪代码):
if a.field1 < b.field1: return true
if a.field1 > b.field1: return false
# field1s is equal here.
return a.field2 < b.field2
答案 2 :(得分:4)
没有。您还需要抓住(a.field1 > b.field1)
。
这不是一个严格的弱排序,因为它会给(1,2) < (2,1)
,但(2,1) < (1,2)
。
答案 3 :(得分:2)
这是一个依赖于逻辑短路规则的版本,以避免显式分支
template<typename T>
bool operator< (T const& a, T const& b)
{
return (
( a.field1 < b.field1 ) || (( a.field1 == b.field1 ) &&
( a.field2 < b.field2 ))
);
}
这假设您的原始类型field1
具有operator==
。为超过2个字段键入此内容会变得很繁琐,但如果您的课程std::lexicographical_compare
将字段存储在obj
内的某些类型std::array<T, N>
和字段{{}},则可以使用T
{1}}
N
请注意,有一份草稿N3326讨论了为类类型自动添加运算符template<typename T, int N>
struct obj
{
std::array<T, N> field;
};
bool operator< (obj const& a, T const& b)
{
return std::lexicographical_compare(
a.field.begin(), a.field.end(),
b.field.begin(), b.field.end()
);
}
和==
。
答案 4 :(得分:0)
下面描述的我的方法涉及一些宏,但在许多情况下仍然有用。也许也可以使用内联函数来完成类似的操作。
#define CMP_LT2(a, b) ((a) < (b) ? (a) : (b))
#define CMP_GT2(a, b) ((a) > (b) ? (a) : (b))
#define CMP_LTE2(a, b) ((a) <= (b) ? (a) : (b))
#define CMP_GTE2(a, b) ((a) >= (b) ? (a) : (b))
#define CMP_EQ2(a, b) ((a) == (b))
#define CMP_NEQ2(a, b) ((a) != (b))
#define CMP_LT3(a, b, c) (CMP_EQ2(a, b) ? (c) : CMP_LT2(a, b))
#define CMP_GT3(a, b, c) (CMP_EQ2(a, b) ? (c) : CMP_GT2(a, b))
#define CMP_LTE3(a, b, c) (CMP_EQ2(a, b) ? (c) : CMP_LT2(a, b))
#define CMP_GTE3(a, b, c) (CMP_EQ2(a, b) ? (c) : CMP_GT2(a, b))
#define CMP_EQ3(a, b, c) ((a) == (b) ? (c) : false)
#define CMP_NEQ3(a, b, c) ((a) != (b) ? true : (c))
然后假设您拥有:
struct Point3D {
double x;
double y;
double z;
};
然后您写:
struct Point3D {
double x;
double y;
double z;
bool operator<(const Point3D& other) const noexcept
{
return CMP_LT3(z, other.z,
CMP_LT3(y, other.y,
CMP_LT2(x, other.x)));
}
};
答案 5 :(得分:0)
您可以在c ++ 11或更高版本中使用可变参数模板
template<typename T>
bool less_than( const T& a, const T& b )
{
return a < b;
}
template<typename T, typename... Args>
bool less_than( const T& a, const T& b, Args... args )
(
if ( a < b )
return true;
else if ( b < a )
return false;
else
return less_than( args... );
)
那你叫
return less_than(a.x,b.x,
a.y,b.y,
a.z,b.z);
只要type具有<运算符,它就支持任意数量的字段或类型。您可以混合类型。