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

使用自定义比较器的std::set::insert报错问题排查

依赖排序struct的编译器错误排查

问题背景

我写了一个小型struct,用来给容器/解决方案里的项目依赖关系排序(实际可用于任意类型排序,仅以std::string作为接口)。依赖关系通过JSON对象定义并导入,使用boost::json完成解析。

示例依赖JSON

"container_dependency_tree": {
    "abc": ["def","hello","world"],
    "def": ["xyz","x","y"],
    "xyz": [],
},

头文件代码

#pragma once

#include <boost/json.hpp>
#include <map>
#include <string>
#include <vector>
#include <set>

namespace tmake {

    struct container_dependency_tree_t {
    private:

        std::map<std::string, std::vector<std::string>>
            m_flat;

        bool
            m_compare(const std::string& lhs, const std::string& rhs) const;//当lhs依赖rhs时返回true

        std::set<std::string, decltype(&m_compare)>
            m_sorted = decltype(m_sorted)(&container_dependency_tree_t::m_compare);

    public:

        container_dependency_tree_t() {}

        container_dependency_tree_t(const boost::json::object& container_dependency_tree);

    public:

        const decltype(m_flat)&
            flat() const;

        const decltype(m_sorted)&
            sorted() const;
    };
}

实现文件代码

#include <tmake/container_dependency_tree_t.h>

namespace tmake {

    container_dependency_tree_t::container_dependency_tree_t(const boost::json::object& container_dependency_tree) {
        for (const auto& kv : container_dependency_tree) {
            std::vector<std::string> dependencies;
            const boost::json::array& dd = kv.value().as_array();
            for (const auto& d : dd) {
                dependencies.push_back(d.as_string().c_str());
            }
            m_flat.emplace(kv.key(), dependencies);
        }

        for (const auto& f : m_flat) {
            m_sorted.insert(f.first);//***错误发生位置***
        }
    }

    bool container_dependency_tree_t::m_compare(const std::string& lhs, const std::string& rhs) const {
        auto find = m_flat.find(lhs);
        if (find == m_flat.end())
            return false;

        for (const auto& dependency : find->second) {
            if (rhs == dependency || m_compare(dependency, rhs)) {
                return true;
            }
        }

        return false;
    }

    const decltype(container_dependency_tree_t::m_flat)& container_dependency_tree_t::flat() const {
        return m_flat;
    }

    const decltype(container_dependency_tree_t::m_sorted)& container_dependency_tree_t::sorted() const {
        return m_sorted;
    }
}

问题

执行m_sorted.insert(f.first);时触发MSVC编译错误:xutility(1372,19): error C2064: 项不会计算为接受2个参数的函数,请问哪里出错了?


错误原因与修复方案

核心问题

你使用非静态成员函数指针作为std::set的比较器,但std::set无法自动绑定类实例。非静态成员函数必须依赖具体的类实例才能调用,而std::set内部调用比较器时,只会传入两个待比较的元素,无法传递当前container_dependency_tree_t的实例,导致编译器无法正确调用m_compare。

修复方案

以下是几种可行的解决方式:

方案1:使用lambda表达式作为比较器(推荐)

调整m_sorted的定义,通过lambda捕获当前实例:

  • 头文件中修改m_sorted声明:
    #include <functional> // 需要包含functional头文件
    using CompareFunc = std::function<bool(const std::string&, const std::string&)>;
    std::set<std::string, CompareFunc> m_sorted;
    
  • 构造函数中初始化m_sorted并插入元素:
    container_dependency_tree_t::container_dependency_tree_t(const boost::json::object& container_dependency_tree) {
        // 解析m_flat的代码保持不变...
    
        // 初始化m_sorted,捕获当前实例指针
        m_sorted = std::set<std::string, CompareFunc>(
            [this](const std::string& lhs, const std::string& rhs) {
                return this->m_compare(lhs, rhs);
            }
        );
    
        // 插入元素
        for (const auto& f : m_flat) {
            m_sorted.insert(f.first);
        }
    }
    
    lambda会持有当前对象的指针,调用m_compare时能正确访问m_flat成员。

方案2:使用自定义functor结构体

定义内部functor,持有类实例的引用:

namespace tmake {
    struct container_dependency_tree_t {
    private:
        struct Compare {
            const container_dependency_tree_t& owner;
            Compare(const container_dependency_tree_t& o) : owner(o) {}
            bool operator()(const std::string& lhs, const std::string& rhs) const {
                return owner.m_compare(lhs, rhs);
            }
        };

        std::map<std::string, std::vector<std::string>> m_flat;
        bool m_compare(const std::string& lhs, const std::string& rhs) const;
        std::set<std::string, Compare> m_sorted;

        // 其他成员声明保持不变

    public:
        container_dependency_tree_t(const boost::json::object& container_dependency_tree)
            : m_sorted(Compare(*this)) { // 初始化时传入当前实例
            // 解析m_flat的代码...
            // 插入元素的代码...
        }
    };
}

这种方式也能让比较器正确访问类的非静态成员。

额外注意点

无论采用哪种方案,都要确保比较器满足严格弱序的要求,否则std::set的行为会未定义。当前m_compare的逻辑是判断lhs是否依赖rhs,需要避免循环依赖导致的a < b且b < a的情况,否则插入元素时会出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:23:13