如何使set :: find()适用于自定义类对象?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使set :: find()适用于自定义类对象?相关的知识,希望对你有一定的参考价值。

我对使用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)));

其中,a1a2是类对象,(ifc是班级成员)。

现在我想为n个成员推广这个,但是我的find()并不总是有效。

我一直在查看STL的详细文档,试图了解set::find()是如何实现的,以及为什么它需要更少(<)运算符重载。

我提到了sgi和msdn文档,但我在那里找不到set::find()的实现细节。

我的set::find()实施中我做错了什么?

答案

您必须定义对象的严格排序。因此,如果您的对象由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方法。它更清洁。

另一答案

您可以使用元组轻松获得成员的词典排序:

return std::tie(lhs.i, lhs.f, lhs.c) < std::tie(rhs.i, rhs.f, rhs.c);

这要求每个成员都具有可比较的类型,例如lhs.i < rhs.i是有道理的。

请注意,std::tiestd::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的扩展接口的一部分(例如,如果没有规范的可能有多个排序是有意义的),那么首选的方法是编写一个仿函数:

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)它必须遵循一些严格的标准,即它必须是严格的弱序。但是,如果用于http://www.sgi.com/tech/stl/set.html排序的所有成员都有SW顺序,则生成的词典排序也是SW排序。

另一答案

std :: set元素比较函数应该在元素域上定义Strict Weak Ordering关系。使用这个定义我们可以说如果compare(a,b)为false且compare(b,a)也为false,则两个元素是等价的。 std :: find可以使用这个假设来实现。 你可以在这里找到更多:http://www.sgi.com/tech/stl/StrictWeakOrdering.htmloperator <

另一答案

你的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

而你实际上不应该对the website of SGI实现感兴趣。它可以从编译器更改为编译器,并且可以在将来进行修改。您的程序应该仅对容器接口做出假设,而不是实现。

另一答案

这只是部分答案,但可以在qazxswpoi上找到STL的详细文档。

以上是关于如何使set :: find()适用于自定义类对象?的主要内容,如果未能解决你的问题,请参考以下文章

adjustsFontForContentSizeCategory 是不是适用于自定义字体?

YOLOv7YOLOv5改进之打印热力图可视化:适用于自定义模型,丰富实验数据

如何将 NSPredicate 应用于自定义 XLForm 行?

在 ng-bootstrap datepicker 中将 CSS 类应用于自定义日期模板

springboot中关于自定义注解校验

如何使 DefaultValueHandling 仅适用于某些类或成员?