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

带自定义比较器的std::map如何让下游用户无需关注比较器即可使用?

问题:带自定义比较器的std::map如何让下游无感知使用?

首先给出自定义对象与带比较器的map定义:

struct Obj
{
    int id;
    std::string data;
    std::vector<std::string> moreData;
};
struct Comparator
{
    using is_transparent = std::true_type;
    bool operator()(Obj const& obj1, Obj const& obj2) { return obj1.id < obj2.id; };
};
std::map<Obj,int,Comparator> compMap;

需求是让下游用户无需处理该自定义比较器即可正常使用此map,但传入如下模板函数时触发类型错误:

template<class T>
inline void add(std::map<T, int>& theMap, T const & keyObj)
{
    auto IT = theMap.find(keyObj);
    if (IT != theMap.end())
        IT->second++;
    else
        theMap[keyObj] = 1;
}
add(compMap,newObj); // 此处触发类型错误

编辑补充:
我之前为简化通用场景忽略了明显方案,将模板修改为:

template<class T, class Comp, class Alloc>
inline void add(std::map<T, int, Comp, Alloc>& theMap, T const & keyObj)

但仍存在T无法推导的问题,不过错误已从80个减少到1个,有进展。


解决方案

1. 最简洁的模板推导修复

你修改后的模板出现T无法推导的问题,是因为编译器无法直接将std::map<T, int, Comp, Alloc>中的T与函数第二个参数的T完成关联推导。换个思路,直接让模板推导整个map类型,而非拆分参数:

template<class Map>
inline void add(Map& theMap, const typename Map::key_type& keyObj)
{
    auto it = theMap.find(keyObj);
    if (it != theMap.end())
        it->second++;
    else
        theMap[keyObj] = 1;
}

这种写法完全不关心map的比较器、分配器参数,只要是标准map类型(具备key_type嵌套类型)就能正常推导,下游用户直接调用add(compMap, newObj)即可,完全感知不到自定义比较器的存在。

2. 利用透明比较器的额外优势(可选)

你的比较器已经声明了is_transparent,这意味着可以扩展支持直接用int查找(无需构造完整Obj),只需补充比较器的重载逻辑:

struct Comparator
{
    using is_transparent = std::true_type;
    bool operator()(const Obj& obj1, const Obj& obj2) { return obj1.id < obj2.id; };
    bool operator()(const Obj& obj, int id) { return obj.id < id; };
    bool operator()(int id, const Obj& obj) { return id < obj.id; };
};

此时add函数甚至可以直接接受int作为key参数(比如add(compMap, 123)),进一步提升灵活性,下游用户依然无需关心比较器细节。

3. 另一种兼容式模板写法

如果不想依赖Map::key_type,也可以用C++11及以上支持的可变参数模板来覆盖所有map参数:

template<class K, class V, class... ExtraArgs>
inline void add(std::map<K, V, ExtraArgs...>& theMap, const K& keyObj)
{
    auto it = theMap.find(keyObj);
    if (it != theMap.end())
        it->second++;
    else
        theMap[keyObj] = 1;
}

这种写法会自动推导键类型K、值类型V以及后续的比较器、分配器等参数,完美解决之前的推导问题。


内容的提问来源于stack exchange,提问作者Sir Demios

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:45:48