如何使 set::find() 为自定义类对象工作?

N D*_*are 4 c++ stl set

我对将 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()实施中做错了什么?

Luc*_*ton 6

您可以使用元组轻松获取成员的字典顺序:

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::tiestd::tuple仅适用于C ++ 11,所以对于C ++ 03可以使用例如Boost.Tuple它确实提供了一个boost::tieboost::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::lessfoo但这有点异国情调,而不是首选方式。如果排序作为扩展接口的一部分仍然没有意义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 排序。


hc_*_*hc_ 5

您必须定义对象的严格顺序。因此,如果您的对象由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方法。干净多了。