【问题标题】:Comparator for member variable of type std::set that requires access to other member variables需要访问其他成员变量的 std::set 类型的成员变量的比较器
【发布时间】:2021-12-06 20:43:35
【问题描述】:

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

但是,为了实现这一点,比较器需要访问m_reference。如何使用需要访问类成员的自定义比较器?我的设计有缺陷吗?我知道有更新的方法可以将比较器提供为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;
};

【问题讨论】:

  • set 排序或免费,但它存储数据的方式使得遍历速度明显慢于vector。如果你做的遍历多于插入,那么简单的插入可能是一个失败的提议。

标签: c++ set comparator


【解决方案1】:

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

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

这是您的代码,已根据这些更改进行了调整。我以为您的意思是 setReferenceinsertShape 是公共接口的一部分。

#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;
};

【讨论】:

  • auto comparator = CenterComparator{}; comparator.reference = m_reference; 可以简化为auto comparator = CenterComparator{m_reference}; 基本上就是CenterComparator comparator{m_reference};
  • 也可以直接将副本分配给m_shapes
猜你喜欢
  • 1970-01-01
  • 2012-12-05
  • 1970-01-01
  • 1970-01-01
  • 2021-11-10
  • 2012-01-26
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
相关资源
最近更新 更多