需要访问其他成员变量的 std::set 类型成员变量的比较器

Comparator for member variable of type std::set that requires access to other member variables

我有一个 class ShapeDisplay 存储一组 Rectangle。我想按顺序存储它们,因此我使用 std::set。我的目的是提供一个自定义比较器,它将矩形的原点 (x, y) 与显示中的参考点 (x, y) 进行比较。

然而,为了实现这一点,比较器需要访问 m_reference。如何使用需要访问 class 成员的自定义比较器?我的设计有缺陷吗?我知道有更新的方法可以将比较器作为 in this link, 提供,但这并不能解决我的访问问题。

或者,我可以只对 std::vector 进行排序,这样每个新的 Rectangle 都会插入正确的位置。但是由于 std::set::insert() 应该使用自定义比较器自动执行此操作,所以我更喜欢那样。

谢谢。

struct Point
{
    int x;
    int y;
};

struct Rectangle
{
    int x;
    int y;
    int width;
    int height;
};

class ShapeDisplay
{
    void insertShape(Rectangle rect)
    {
        m_shapes.insert(rect);
    }

    void setReference(Point reference)
    {
        m_reference = reference;
    }

private: 
    struct CenterComparator
    {
        bool operator() (const Rectangle & a, const Rectangle & b) const 
        {
            
            double distA = std::sqrt(std::pow(a.x - m_reference.x, 2) 
                                   + std::pow(a.y - m_reference.y, 2)); 

            double distB = std::sqrt(std::pow(b.x - m_reference.x, 2) 
                                   + std::pow(b.y - m_reference.y, 2)); 

            return distA < distB;
        }
    };

    std::set<Rectangle, CenterComparator> m_shapes;
    Point m_reference;
};

CenterComparatorShapeDisplay 无关,它不知道其成员,也不是从 ShapeDisplay 派生的。您需要为 CenterComparator 提供它自己的引用 Point。然后您需要提供 CenterComparator 的实例,其参考点已设置。

请注意,如果您以任何方式更改该比较器的参考点,您将破坏 std::set 的排序,如果您尝试使用它会导致未定义的行为。因此,每当调用 setReference 时,您都需要使用新比较器创建一个新集合并复制旧集合。

这是您的代码,根据这些更改进行了调整。我假设你的意思是 setReferenceinsertShape 是 public 接口的一部分。

#include <cmath>
#include <set>

struct Point
{
    int x;
    int y;
};

struct Rectangle
{
    int x;
    int y;
    int width;
    int height;
};

class ShapeDisplay
{
public:
    void insertShape(Rectangle rect)
    {
        m_shapes.insert(rect);
    }

    void setReference(Point reference)
    {
        m_reference = reference;

        // Create a comparator using this new reference
        auto comparator = CenterComparator{};
        comparator.reference = m_reference;

        // Create a new set
        auto new_shapes = std::set<Rectangle, CenterComparator>(
            std::begin(m_shapes), std::end(m_shapes),   // Copy these shapes
            comparator);                                // Use this comparator

        m_shapes = std::move(new_shapes);
    }

private: 
    struct CenterComparator
    {
        bool operator() (const Rectangle & a, const Rectangle & b) const 
        {
            
            double distA = std::sqrt(std::pow(a.x - reference.x, 2) 
                                   + std::pow(a.y - reference.y, 2)); 

            double distB = std::sqrt(std::pow(b.x - reference.x, 2) 
                                   + std::pow(b.y - reference.y, 2)); 

            return distA < distB;
        }

        Point reference;
    };

    std::set<Rectangle, CenterComparator> m_shapes;
    Point m_reference;
};