如何让std::set的嵌套比较器访问外部类非静态成员?
解决std::set自定义比较器访问外部类非静态成员的问题
问题描述
需要在类A中维护一个存储B类对象的std::set,自定义比较结构体Comp需要访问A的非静态成员m_t来执行比较,但原代码无法编译——内部结构体Comp无法直接访问外部类的非静态成员,且不想将m_t设为静态。
原错误代码示例:
class B { ... }; class A { struct Comp { bool operator()(B b1, B b2) const { // 此处需要使用m_t比较b1和b2,但无法直接访问 } }; std::set<B, Comp> m_set; double m_t; };
背景补充:这是为实现扫描线算法,B类的函数依赖m_t(取值范围0到1),且这些函数在[0,1]区间内不会相交,因此B对象间的比较结果固定,可保证std::set的有序性不受破坏。当扫描线处于指定m_t值时,需查询集合中包围某个值的函数。
可行解决方案
核心思路是让自定义比较器Comp持有外部类A的指针或引用,从而合法访问m_t。需注意保证比较器持有的引用/指针生命周期与std::set一致,避免悬空引用。
方法1:让Comp持有A的指针
修改Comp结构体,添加指向A的指针成员,初始化std::set时传入绑定当前A对象的Comp实例:
class B { ... }; class A { struct Comp { A* parent; // 构造函数接收外部类指针 Comp(A* p) : parent(p) {} bool operator()(const B& b1, const B& b2) const { // 通过parent指针访问m_t return b1.some_func(parent->m_t) < b2.some_func(parent->m_t); } }; std::set<B, Comp> m_set; double m_t; public: A() : m_set(Comp(this)) { // 初始化set时传入绑定当前对象的Comp m_t = 0.0; // 初始化m_t } };
方法2:让Comp持有A的引用(需严格保证生命周期)
如果能确保A对象的生命周期长于m_set,也可以使用引用:
class B { ... }; class A { struct Comp { A& parent; Comp(A& p) : parent(p) {} bool operator()(const B& b1, const B& b2) const { return b1.some_func(parent.m_t) < b2.some_func(parent.m_t); } }; std::set<B, Comp> m_set; double m_t; public: A() : m_set(Comp(*this)) { m_t = 0.0; } };
关键注意事项
- 必须保证
m_t的值在std::set的生命周期内不会改变比较结果的顺序(这一点已通过扫描线算法的背景保证),否则会破坏std::set的有序性,导致未定义行为。 - 比较器的
operator()必须是const成员函数,若需要修改m_t,可考虑将m_t声明为mutable,但需确保修改后不会影响对象间的比较逻辑。
内容的提问来源于stack exchange,提问作者Willem3141
相关产品推荐
相关产品推荐

