You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为类内关联的set容器指定自定义比较器?

问题描述

需要为MyClass类的私有成员mbp(类型为map<unsigned, set<string, Compare>>)中的set容器指定自定义比较器。该比较器不直接比较string类型的键,而是通过键访问类内的ob成员(map<string, MyStruct>),获取对应MyStruct的p和t属性,按照先按p降序,p相同时按t升序的规则完成比较。

尝试过类内结构体、仿函数、bind三种实现方式均出错,需找到可行方案以节省内存。

代码示例:

struct MyStruct {
    unsigned p;
    unsigned t;
};

class MyClass {
public:
    void call() {
        ob["o1_10"] ={10, 1};
        mbp[ob["o1_10"].p].insert("o1_10");

        ob["o2_20_2"] ={20, 2};
        mbp[ob["o2_20"].p].insert("o2_20");


        ob["o4_4_4"] ={4, 4};
        mbp[ob["o4_4"].p].insert("o4_4");

        ob["o5_10"] ={10, 4};
        mbp[ob["o5_10"].p].insert("o5_10");
    }
    
    
private:
    map<unsigned,set<string, Compare>> mbp;
    // 需求:通过自定义比较器,利用ob中存储的MyStruct的p和t属性进行比较,而非直接比较string键
    // 示例逻辑:
    // bool compare(const string& o1, const string& o2) const {
    //     if (ob.at(o1).p > ob.at(o2).p)   return true;
    //     if (ob.at(o1).p == ob.at(o2).p && ob.at(o1).t < ob.at(o2).t) return true;
    //     return false;
    // }
    
    map<string, MyStruct> ob;
};


int main() {
    MyClass my_class;
    my_class.call();

    return 0;
}

注:比较逻辑依赖通过string键访问类内ob中的MyStruct实例属性,而非直接比较string本身。


可行实现方案

核心思路

自定义带状态的仿函数作为比较器,让其持有MyClass实例的const引用,从而安全访问私有成员ob。同时注意set的构造方式,因为带状态的比较器无法默认构造,需显式传入实例。

完整代码实现

#include <map>
#include <set>
#include <string>

struct MyStruct {
    unsigned p;
    unsigned t;
};

class MyClass {
    // 内部定义带状态的比较器结构体
    struct Compare {
        const MyClass& parent;
        // 必须通过构造函数传入MyClass实例引用
        explicit Compare(const MyClass& ref) : parent(ref) {}

        bool operator()(const std::string& o1, const std::string& o2) const {
            // 从ob中获取对应的MyStruct,这里假设所有传入的键都存在于ob中
            const MyStruct& s1 = parent.ob.at(o1);
            const MyStruct& s2 = parent.ob.at(o2);
            
            if (s1.p != s2.p) {
                return s1.p > s2.p; // 按p降序排序
            } else {
                return s1.t < s2.t; // p相同时按t升序排序
            }
        }
    };

public:
    void call() {
        // 先初始化ob的元素(修正原代码中的键名不一致问题)
        ob["o1_10"] = {10, 1};
        ob["o2_20"] = {20, 2};
        ob["o4_4"] = {4, 4};
        ob["o5_10"] = {10, 4};

        // 封装插入逻辑:避免直接用mbp[]默认构造set
        auto insert_to_mbp = [this](unsigned p_key, const std::string& str_key) {
            auto it = mbp.find(p_key);
            if (it == mbp.end()) {
                // 当p对应的set不存在时,显式传入比较器实例构造set
                it = mbp.emplace(p_key, Compare(*this)).first;
            }
            it->second.insert(str_key);
        };

        // 执行插入操作
        insert_to_mbp(ob["o1_10"].p, "o1_10");
        insert_to_mbp(ob["o2_20"].p, "o2_20");
        insert_to_mbp(ob["o4_4"].p, "o4_4");
        insert_to_mbp(ob["o5_10"].p, "o5_10");
    }
    
private:
    std::map<unsigned, std::set<std::string, Compare>> mbp;
    std::map<std::string, MyStruct> ob;
};

int main() {
    MyClass my_class;
    my_class.call();
    return 0;
}

关键细节说明

  1. 比较器设计:

    • Compare作为MyClass的内部结构体,持有MyClass的const引用,既能访问私有成员ob,又保证比较操作不会修改类实例状态。
    • 比较逻辑严格遵循需求:先按p降序,p相等时按t升序。
  2. set构造方式:

    • 由于Compare没有默认构造函数(必须传入MyClass引用),无法使用mbp[p_key]的默认构造行为,改用find+emplace组合,显式传递Compare(*this)构造set。
  3. 键存在性处理:

    • 示例中使用ob.at()获取元素,若键不存在会抛出std::out_of_range异常。如果需要容错,可替换为ob.find()并添加键不存在的处理逻辑:
      bool operator()(const std::string& o1, const std::string& o2) const {
          auto it1 = parent.ob.find(o1);
          auto it2 = parent.ob.find(o2);
          // 假设键不存在时视为相等或按默认规则处理,可根据需求调整
          if (it1 == parent.ob.end() || it2 == parent.ob.end()) return false;
          const MyStruct& s1 = it1->second;
          const MyStruct& s2 = it2->second;
          if (s1.p != s2.p) return s1.p > s2.p;
          return s1.t < s2.t;
      }
      

为什么之前的方案出错

  • 类内成员函数:普通成员函数需要绑定this指针才能作为可调用对象,但set的比较器类型要求固定,无法直接传递成员函数指针。
  • 无状态仿函数:无法访问MyClass的私有成员ob,除非破坏封装性将ob改为全局变量。
  • bind方式:std::bind返回的std::function可以作为比较器,但会带来额外的性能开销,且需要严格保证绑定的this指针生命周期,不如自定义带引用的仿函数高效。

内容的提问来源于stack exchange,提问作者Maryam Shabani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:14:52