使用自定义比较器的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并插入元素:
lambda会持有当前对象的指针,调用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); } }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
相关产品推荐
相关产品推荐

