如何创建 std::set 结构?

2021-12-23 00:00:00 set containers struct c++ stl

我需要创建一个 stl::set 结构.因此,我写了以下内容:

I need to create a stl::set of structures. Therefore, I wrote the following:

stl::set <Point> mySet; // Point - name of the structure.

然后我尝试将结构实例添加到 mySet 中,如下所示:

Then I tried to add a structure instance to mySet as follows:

Point myPoint;
mySet.insert(myPoint);

但是,我收到了几个编译错误(错误 C2784、错误 C2676):

However, I get several compilation errors (error C2784, error C2676):

1>C:Program Files (x86)Microsoft Visual Studio 10.0VCincludexfunctional(125): error C2784: bool std::operator <(const std::vector<_Ty,_Ax> &;,const std::vector<_Ty,_Ax> &): 未能将参数带入模板const std::vector<_Ty,_Ax>&"来自const点"

1>C:Program Files (x86)Microsoft Visual Studio 10.0VCincludexfunctional(125): error C2784: bool std::operator <(const std::vector<_Ty,_Ax> &,const std::vector<_Ty,_Ax> &): failed to bring the argument to a template "const std::vector<_Ty,_Ax> &" from"const Point"

1>C:Program Files (x86)Microsoft Visual Studio 10.0VCincludexfunctional(125): error C2676: binary<":const Point"没有定义这个操作符或转换为集成运算符可接受的类型

1>C:Program Files (x86)Microsoft Visual Studio 10.0VCincludexfunctional(125): error C2676: binary "<": "const Point "does not define this operator or a conversion to a type acceptable to the integrated operator

如何编译我的代码?

推荐答案

std::set 模板提供了一个关联容器,其中包含一组排序的唯一对象.那里的关键词是排序和独特.为了支持排序,许多可能性随之而来,但最终所有的可能性都必须导致符合 strict weak订购.

The std::set template provides an associative container that contains a sorted set of unique objects. The key words there is sorted and unique. To support sorting, a number of possibilities ensue, but ultimately the all must lead to a conforming with strict weak ordering.

std::set 的第二个模板参数是 comparison 类型.默认值 std::less 由标准库提供,其中 Key 是您存储在容器中的对象类型(在您的情况下, ).该默认值仅使用支持密钥类型的任何允许的可用 operator < 生成比较.这意味着一种或另一种方式,如果您使用默认比较器(在您的情况下为 std::less),那么您的类必须假设如下操作:

The second template argument to std::set is a comparison type. The default, std::less<Key>, is supplied by the standard library, where Key is the type of object you're storing in your container (in your case, Point). That default simply generates a comparison using any allowable available operator < supporting the key type. Which means one way or another, if you're using the default comparator (std::less<Point> in your case), then your class must suppose operations like this:

Point pt1(args);
Point pt2(args);

if (pt1 < pt2)  // <<=== this operation
    dosomething();

执行此操作的多种方法如下所示:

Multiple methods for doing this appear below:

提供成员operator <

到目前为止,最简单的方法是为您的 Point 类提供一个成员 operator <.这样做 pt1 变得有效并且 std::less 然后很高兴.假设您的类是传统的 x,y 点,它看起来像这样:

By far the easiest method to accomplish this is to provide a member operator < for your Point class. In doing so pt1 < pt2 becomes valid and std::less<Point> is then happy. Assuming your class is a traditional x,y point, it would look like this:

struct Point
{
    int x,y;

    // compare for order.     
    bool operator <(const Point& pt) const
    {
        return (x < pt.x) || ((!(pt.x < x)) && (y < pt.y));
    }
};

<小时>

提供自定义比较器类型

另一种方法是提供自定义比较器类型,而不是依赖于 std::less.这方面的最大优势是能够定义几个可能意味着不同事物的东西,并根据需要在容器或算法中使用它们.

Another method would be to provide a custom comparator type rather than relying on std::less<Point>. The biggest advantage in this is the ability to define several that can mean different things, and use them in containers or algorithms as appropriately needed.

struct CmpPoint
{
    bool operator()(const Point& lhs, const Point& rhs) const
    {
        return (lhs.x < rhs.x) || ((!(rhs.x < lhs.x)) && (lhs.y < rhs.y));
    }
};

有了它,您现在可以像这样声明您的 std::set:

With that, you can now declare your std::set like this:

std::set<Point,CmpPoint> mySet;

使用这种方法需要考虑的一些事情:类型不是 Point 的一部分,因此任何对私有成员变量或函数的访问都必须通过增加能力来考虑.

Something to consider with this approach: The type is not part of Point, so any access to private member variables or functions has to be accounted for via friending in come capacity.

提供一个自由函数operator <

另一种不太常见的机制是简单地提供一个全局自由函数,该函数提供 operator <.这不是成员函数.再次执行此操作时,默认的 std::less 将生成有效代码.

Another less common mechanism is simply provide a global free-function that provides operator <. This is NOT a member function. In doing this, once again, the default std::less<Point> will result in valid code.

bool operator <(const Point& lhs, const Point& rhs)
{
    return (lhs.x < rhs.x) || ((!(rhs.x < lhs.x)) && (lhs.y < rhs.y));
}

这似乎是自定义比较器和成员运算符的混合体,实际上它们各有优缺点.例如:就像成员operator <,你可以使用默认的std::less.与自定义比较器一样,这是一个非类函数,因此必须通过友元或访问器提供对私有成员的访问.

This may seem a mix of both the custom comparator and the member operator, and indeed many of the pros and cons of each come along. Ex: like the member operator <, you can just use the default std::less<Point>. Like the custom comparator, this is a non-class function, so access to private members must be provided via friending or accessors.

总结

根据您的需要,我会采用简单的方法;只需创建一个成员operator <.您可能总是希望以这种方式订购您的 Point.如果没有,请使用自定义比较器.在任一情况下,请确保遵守严格的弱排序.

For your needs, I'd go with the simple approach; just make a member operator <. Chances are you'll always want to order your Points in that fashion. If not, go with the custom comparator. In either case make sure you honor strict weak ordering.

相关文章