我对将 STLset::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)));
Run Code Online (Sandbox Code Playgroud)
其中, a1, anda2是类对象, ( i, fandc是类成员)。
现在我想对 n 个成员进行概括,但我的find()并不总是有效。
我一直在查看 STL 的详细文档,试图了解它set::find()是如何实现的,以及为什么它需要 less ( <) 运算符重载。
我参考了 sgi 和 msdn 文档,但我也找不到太多关于set::find()那里的实现细节。
我在set::find()实施中做错了什么?
您可以使用元组轻松获取成员的字典顺序:
return std::tie(lhs.i, lhs.f, lhs.c) < std::tie(rhs.i, rhs.f, rhs.c);
Run Code Online (Sandbox Code Playgroud)
这要求每个成员都具有可比较的类型,例如lhs.i < rhs.i有意义。
请注意,std::tie并std::tuple仅适用于C ++ 11,所以对于C ++ 03可以使用例如Boost.Tuple它确实提供了一个boost::tie(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);
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它不是完全自动的,因为实现operator<需要列出每个成员foo(或至少那些对排序很重要的成员),两次。恐怕没有更好的办法了。
而不是提供operator<您可以专攻的方法std::less,foo但这有点异国情调,而不是首选方式。如果排序作为扩展接口的一部分仍然没有意义foo(例如,可能有多个排序在没有规范的情况下有意义),那么首选的方法是编写一个函子:
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< */
}
};
Run Code Online (Sandbox Code Playgroud)
然后你会使用 eg std::set<foo, foo_ordering>。
请注意,无论排序采用什么形式(通过operator<,std::less<foo>或函子),如果它与std::set或任何其他关联容器一起使用(默认情况下,例如std::set<T>使用std::less<T>,默认情况下使用operator<),它必须遵循一些严格的标准,即它必须是严格的弱排序。但是,如果用于foo排序的所有成员本身都具有 SW 排序,则生成的字典顺序也是 SW 排序。
您必须定义对象的严格顺序。因此,如果您的对象由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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
如果您可以选择 boost 或 C++11,那么您真的应该使用Luc Danton 在他的回答中建议的std::tie/boost::tie方法。干净多了。