我对使用STL set::find()
一组我自己定义的类对象感到有点困惑。
我的课程包含两个以上的项目(3/4/5等),那么如何重载less
运算符?
我尝试了3变量,如下所示并正常工作:
return( (a1.i < a2.i) ||
(!(a1.i > a2.i) && (a1.f < a2.f)) ||
(!(a1.i > a2.i) && !(a1.f > a2.f) && (a1.c < a2.c)));
其中,a1
和a2
是类对象,(i
,f
和c
是类成员。)
现在我想对n个成员进行概括,但我的find()
并不总是有效。
我一直在查看STL的详细文档,试图了解set::find()
的实现方式,以及为什么它需要较少的(<
)运算符重载。
我提到了sgi和msdn文档,但我在那里找不到set::find()
的实现细节。
我的set::find()
实施中我做错了什么?
答案 0 :(得分:4)
您必须定义对象的严格排序。因此,如果您的对象由n
成员a_1
... a_n
组成,所有成员都有严格的排序,您可以做的是:
bool operator< (const TYPE &rhs) {
if (a_1 < rhs.a_1) return true; else if (a_1 > rhs.a_1) return false;
if (a_2 < rhs.a_2) return true; else if (a_2 > rhs.a_2) return false;
...
if (a_n < rhs.a_n) return true;
return false;
}
修改强>
如果你可以选择使用boost或C ++ 11,你应该选择Luc Danton在答案中建议的std::tie
/ boost::tie
方法。它更干净。
答案 1 :(得分:4)
您可以使用元组轻松获得成员的词典排序:
return std::tie(lhs.i, lhs.f, lhs.c) < std::tie(rhs.i, rhs.f, rhs.c);
这要求每个成员都具有可比性,例如: lhs.i < rhs.i
是有道理的。
请注意,std::tie
和std::tuple
仅适用于C ++ 11,因此对于C ++ 03,您可以使用例如提供boost::tie
(boost::tuple
的Boost.Tuple使用与std::tuple
相同的排序。)
至于应该去哪里,习惯上把它放在operator<
中(毕竟这是使用tie
以便在一开始就可以轻松订购的原因)。这个操作员经常会成为朋友,所以这看起来像是:
class foo {
public:
/* public interface goes here */
// declaration of non-member friend operator
// if it doesn't need to be a friend, this declaration isn't needed
friend
bool operator<(foo const& lhs, foo const& rhs);
private:
T t;
U u;
V v;
};
bool operator<(foo const& lhs, foo const& rhs)
{
// could be boost::tie
return std::tie(lhs.t, lhs.u, lhs.v) < std::tie(rhs.t, rhs.u, rhs.v);
}
正如您所看到的那样,它不是完全自动的,因为operator<
的实现需要列出foo
的每个成员(或者至少是那些对排序很重要的成员),两次。我害怕没有更好的方式。
您可以为operator<
专门设置std::less
,而不是提供foo
,但这有点奇特而不是首选方式。如果成为foo
的扩展接口的一部分仍然没有意义排序(例如,如果没有规范的可能有多个有序的排序),那么首选的方法是编写一个仿函数: / p>
struct foo_ordering {
bool operator()(foo const& lhs, foo const& rhs) const
{
/* implementation as before, but access control/friendship
has to be planned for just like for operator< */
}
};
然后你会使用例如std::set<foo, foo_ordering>
。
请注意,无论排序采用何种形式(通过operator<
,std::less<foo>
或仿函数),如果它与std::set
或任何其他关联容器一起使用(以及默认情况下,例如std::set<T>
使用std::less<T>
,默认情况下使用operator<
)它必须遵循一些严格的标准,即它必须是严格的弱排序。但是,如果用于foo
排序的所有成员都有SW顺序,则生成的词典排序也是SW顺序。
答案 2 :(得分:2)
std :: set元素比较函数应该在元素域上定义Strict Weak Ordering关系。使用这个定义我们可以说如果compare(a,b)为false且compare(b,a)也为false,则两个元素是等价的。 std :: find可以使用这个假设来实现 您可以在此处找到更多信息:http://www.sgi.com/tech/stl/set.html和http://www.sgi.com/tech/stl/StrictWeakOrdering.html
答案 3 :(得分:1)
您的operator <
应该能够将每个对象与给定的对象进行比较,就像那样
struct Data
{
bool operator < (const Data& right) const
{
return( (this.i < right.i) ||
(!(this.i > right.i) && (this.f < right.f)) ||
(!(this.i > right.i) && !(this.f > right.f) && (this.c < right.c)));
}
}
此外,您的比较算法看起来很可疑,因为它不会考虑案例,
this.i == right.i
或
this.f == right.f
您实际上不应该对std::set
实施感兴趣。它可以从编译器更改为编译器,并且可以在将来进行修改。您的程序应仅对容器接口进行假设,而不是实现。
答案 4 :(得分:1)
这只是部分答案,但可以在the website of SGI找到详细的STL文档。