如何正确使用C++中set的.find()函数?自定义point结构体引发匹配错误
定义了如下point结构体:
struct point { double x; double y; };
编写isChecked函数时,使用set<vector<point>>的.find()函数出现错误,鼠标悬停提示In template: invalid operands to binary expression ('const point' and 'const point'),函数代码如下:
bool isChecked(point left, point right, set<vector<point>>const& inSet) { // 检查点的两种排列组合 vector<point> tmp1 = {left, right}; vector<point> tmp2 = {right, left}; // .find()返回找到元素的迭代器,未找到则返回.end() auto first = inSet.find(tmp1); auto second = inSet.find(tmp2); // 判断是否已检查过该点对 if (first != inSet.end() || second != inSet.end()) return true; return false; }
编译器给出的错误信息:
C:/msys64/mingw64/include/c++/12.2.0/bits/predefined_ops.h:45:23: error: no match for 'operator<' (operand types are 'const point' and 'const point') 45 | { return *__it1 < *__it2; } | ~~~~~~~^~~~~~~~ In file included from C:/msys64/mingw64/include/c++/12.2.0/string:47: C:/msys64/mingw64/include/c++/12.2.0/bits/stl_iterator.h:1246:5: note: candidate: 'template<class _IteratorL, class _IteratorR, class _Container> bool __gnu_cxx::operator<(const __normal_iterator<_IteratorL, _Container>&, const __normal_iterator<_IteratorR, _Container>&)' 1246 | operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, | ^~~~~~~~ C:/msys64/mingw64/include/c++/12.2.0/bits/stl_iterator.h:1246:5: note: template argument deduction/substitution failed: C:/msys64/mingw64/include/c++/12.2.0/bits/predefined_ops.h:45:23: note: 'const point' is not derived from 'const __gnu_cxx::__normal_iterator<_IteratorL, _Container>' 45 | { return *__it1 < *__it2; } | ~~~~~~~^~~~~~~~ C:/msys64/mingw64/include/c++/12.2.0/bits/stl_iterator.h:1254:5: note: candidate: 'template<class _Iterator, class _Container> bool __gnu_cxx::operator<(const __normal_iterator<_Iterator, _Container>&, const __normal_iterator<_Iterator, _Container>&)' 1254 | operator<(const __normal_iterator<_Iterator, _Container>& __lhs, | ^~~~~~~~ C:/msys64/mingw64/include/c++/12.2.0/bits/stl_iterator.h:1254:5: note: template argument deduction/substitution failed: C:/msys64/mingw64/include/c++/12.2.0/bits/predefined_ops.h:45:23: note: 'const point' is not derived from 'const __gnu_cxx::__normal_iterator<_Iterator, _Container>' 45 | { return *__it1 < *__it2; } | ~~~~~~~^~~~~~~~ ninja: build stopped: subcommand failed.
C++标准库的set是有序容器,默认依赖<运算符完成元素排序和比较。对于set<vector<point>>,比较逻辑会递归到vector内部的元素——也就是point对象,但自定义的point结构体没有重载<运算符,编译器无法判断两个point的大小关系,导致.find()调用失败。
有三种可行的解决方式:
方法一:为point重载<运算符
直接在point结构体中定义operator<,实现明确的比较逻辑(比如先比x坐标,x相等再比y坐标):
struct point { double x; double y; // 重载小于运算符,必须是const成员函数 bool operator<(const point& other) const { if (x != other.x) return x < other.x; return y < other.y; } };
完成后,vector<point>的比较会自动使用该运算符,set的.find()即可正常工作。
方法二:给set传入自定义比较器
如果不想修改point结构体,可以定义独立的比较规则,作为set的模板参数:
// 自定义比较器结构体 struct PointVectorCompare { bool operator()(const vector<point>& a, const vector<point>& b) const { if (a.size() != b.size()) return a.size() < b.size(); // 逐个比较vector中的point元素 for (size_t i = 0; i < a.size(); ++i) { if (a[i].x != b[i].x) return a[i].x < b[i].x; if (a[i].y != b[i].y) return a[i].y < b[i].y; } return false; } }; // 使用自定义比较器声明set set<vector<point>, PointVectorCompare> inSet;
这种方式无需改动point本身,直接为set指定专属的比较逻辑。
方法三:改用unordered_set(需定义哈希与相等规则)
如果不需要有序存储,可以改用基于哈希的unordered_set,但需要为point和vector<point>分别定义==运算符和哈希函数:
struct point { double x; double y; // 重载相等运算符 bool operator==(const point& other) const { return x == other.x && y == other.y; } }; // 为point定义哈希函数 namespace std { template<> struct hash<point> { size_t operator()(const point& p) const { // 组合x和y的哈希值,可根据需求调整实现 size_t hash_x = hash<double>()(p.x); size_t hash_y = hash<double>()(p.y); return hash_x ^ (hash_y << 1); } }; // 为vector<point>定义哈希函数 template<> struct hash<vector<point>> { size_t operator()(const vector<point>& vec) const { size_t result = 0; for (const auto& p : vec) { result ^= hash<point>()(p) + 0x9e3779b9 + (result << 6) + (result >> 2); } return result; } }; } // 使用unordered_set unordered_set<vector<point>> inSet;
注意:浮点数存在精度问题,如果x/y可能有精度误差,建议先做截断或取整处理再计算哈希。
另外,从你的函数逻辑来看,可优化点对的存储方式:插入集合时统一存储有序点对(比如始终把x较小的点放在前面,x相等则y较小的在前),这样查找时只需生成一个有序vector,无需两次查找,能提升效率。
内容的提问来源于stack exchange,提问作者Jack Hermanson

