为std::map实现排序比较器时遭遇编译错误,寻求技术支持
问题:无法使用std::sort对std::map按欧氏距离排序
问题背景
尝试为std::map实现自定义比较器,通过std::sort基于欧氏距离对map元素(键为ID,值为坐标向量)排序,代码如下:
#include <iostream> #include <vector> #include <map> #include <cmath> #include <algorithm> namespace NONBCG_DATA_ALGO { template<typename T> T distance(std::vector<T> P1, std::vector<T> P2 , int dim) { if ((typeid(T) == typeid(int)) || (typeid(T) == typeid(double)) || (typeid(T) == typeid(float)) ) { float accum = 0; for(int i=0; i<dim; i++) { accum += pow((P2[i]-P1[i]),2); } return sqrt(accum); } else { throw std::invalid_argument("Type should be either int,double or float"); } } template<typename T> class distance_compare_asc_comp_id_2D { public: distance_compare_asc_comp_id_2D(std::vector<T> ipt):Pt(ipt){}; bool operator()(const std::pair<int,std::vector<T>>& p1,const std::pair<int,std::vector<T>>&p2) { if ((typeid(T) == typeid(int)) || (typeid(T) == typeid(double)) || (typeid(T) == typeid(float)) ) { return NONBCG_DATA_ALGO::distance<T>(Pt,p1.second,2) < NONBCG_DATA_ALGO::distance(Pt,p2.second,2); } else { throw std::invalid_argument("Type should be either int,double or float"); } } private: std::vector<T> Pt; }; }; int main() { // Write C++ code here std::map<int,std::vector<double>> right; right.insert(std::pair<int,std::vector<double>>(1,{2,8,3})); right.insert(std::pair<int,std::vector<double>>(6,{2.5,5.4,3})); sort(right.begin(),right.end(),NONBCG_DATA_ALGO::distance_compare_asc_comp_id_2D<double>(std::vector<double>{0.0,0.0})); return 0; }
编译错误信息
In file included from /usr/include/c++/9/algorithm:62, from /tmp/wxeRdlKRUn.cpp:6: /usr/include/c++/9/bits/stl_algo.h: In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_Rb_tree_iterator<std::pair<const int, std::vector<double> > >; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<NONBCG_DATA_ALGO::distance_compare_asc_comp_id_2D<double> >]': /usr/include/c++/9/bits/stl_algo.h:4899:18: required from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_Rb_tree_iterator<std::pair<const int, std::vector<double> > >; _Compare = NONBCG_DATA_ALGO::distance_compare_asc_comp_id_2D<double>]': /tmp/wxeRdlKRUn.cpp:70:122: required from here /usr/include/c++/9/bits/stl_algo.h:1968:22: error: no match for 'operator-' (operand types are 'std::_Rb_tree_iterator<std::pair<const int, std::vector<double> > >' and 'std::_Rb_tree_iterator<std::pair<const int, std::vector<double> > >') 1968 | std::__lg(__last - __first) * 2, | ~~~~~~~^~~~~~~~~
解决方案
错误原因
std::map的底层是红黑树结构,其迭代器属于双向迭代器,仅支持++/--操作;而std::sort要求迭代器必须是随机访问迭代器(需支持operator-、operator[]等随机访问操作),因此直接对std::map调用std::sort会触发编译错误。
解决步骤
- 将
std::map中的元素复制到支持随机访问的容器(如std::vector) - 对
std::vector使用自定义比较器执行排序 - 若需要保留排序结果,直接操作vector即可(
std::map本身始终按键有序,无法修改其内部元素顺序)
修改后的代码示例
#include <iostream> #include <vector> #include <map> #include <cmath> #include <algorithm> #include <type_traits> namespace NONBCG_DATA_ALGO { // 优化:用const引用传递vector避免拷贝,编译期检查类型合法性 template<typename T> T distance(const std::vector<T>& P1, const std::vector<T>& P2, int dim) { static_assert(std::is_arithmetic_v<T>, "Type must be arithmetic (int, double, float)"); double accum = 0.0; for(int i = 0; i < dim; ++i) { double diff = P2[i] - P1[i]; accum += diff * diff; // 替换pow提升计算效率 } return static_cast<T>(sqrt(accum)); } template<typename T> class distance_compare_asc_comp_id_2D { public: distance_compare_asc_comp_id_2D(const std::vector<T>& ipt) : Pt(ipt) {}; bool operator()(const std::pair<int, std::vector<T>>& p1, const std::pair<int, std::vector<T>>& p2) { static_assert(std::is_arithmetic_v<T>, "Type must be arithmetic (int, double, float)"); return NONBCG_DATA_ALGO::distance(Pt, p1.second, 2) < NONBCG_DATA_ALGO::distance(Pt, p2.second, 2); } private: std::vector<T> Pt; }; }; int main() { std::map<int, std::vector<double>> right; right.insert({1, {2, 8, 3}}); right.insert({6, {2.5, 5.4, 3}}); // 1. 将map元素复制到vector std::vector<std::pair<int, std::vector<double>>> sorted_vec(right.begin(), right.end()); // 2. 对vector执行排序 std::sort(sorted_vec.begin(), sorted_vec.end(), NONBCG_DATA_ALGO::distance_compare_asc_comp_id_2D<double>({0.0, 0.0})); // 输出排序结果 for(const auto& elem : sorted_vec) { std::cout << "ID: " << elem.first << ", 坐标: [" << elem.second[0] << ", " << elem.second[1] << "]" << ", 距离原点: " << NONBCG_DATA_ALGO::distance<double>({0.0,0.0}, elem.second, 2) << "\n"; } return 0; }
额外优化说明
- 用
static_assert替代typeid检查,在编译期拦截非法类型,避免运行时异常 - 传递vector时使用
const&减少不必要的拷贝操作 - 用
diff * diff替代pow(diff,2),提升数值计算效率
内容的提问来源于stack exchange,提问作者siva_uchiha
相关产品推荐
相关产品推荐

