未调用std::equal_to<void>却触发C3889错误?求技术解答
C3889错误分析与解决方案
开发大型C++项目时,使用Visual Studio 2022持续触发C3889错误,错误信息如下:
error C3889: call to object of class type 'std::equal_to<void>': no matching call operator found note: could be 'unknown-type std::equal_to<void>::operator ()(_Ty1 &&,_Ty2 &&) noexcept(<expr>) const' note: Failed to specialize function template 'unknown-type std::equal_to<void>::operator ()(_Ty1 &&,_Ty2 &&) noexcept(<expr>) const' note: With the following template arguments: note: '_Ty1=const _Ty &' note: '_Ty2=const _Ty &' note: binary '==': 'const _Ty' does not define this operator or a conversion to a type acceptable to the predefined operator with [ _Ty=Spot ]
未显式调用std::equal_to<void>却出现该错误,最小复现示例(MRE)如下:
#include <iostream> #include <vector> template <typename T> bool isin(T i, const std::vector<T>& vec) { for (const T& t : vec) { if (i == t) return true; } return false; } template <typename T> std::vector<std::vector<T>> GetAllUniqueCombos(const std::vector<T>& arr) { std::vector<std::vector<T>> n; for (int i = 0; i < arr.size(); ++i) { for (int j = i + 1; j < arr.size(); ++j) { if (!isin({ arr[i], arr[j] }, n))n.push_back({ arr[i], arr[j] }); } } return n; } struct Spot { int x, y; }; void DrawTriangle(Spot s1, Spot s2, Spot s3, int color); void DrawPolygon(const std::vector<Spot>& points, int color) { if (points.size() < 3) return; std::vector<Spot> a; for (int j = 1; j < points.size(); j++) { a.push_back(points[j]); } for (auto i : GetAllUniqueCombos(a)) { DrawTriangle(points[0], i[0], i[1], color); } } int main() { DrawPolygon({ {25, 25}, {50, 50}, {25, 50}, {50, 25} }, 0xffaa55); }
错误原因
- 核心问题:
std::vector的==依赖元素的相等运算符
当isin函数的模板参数T推导为std::vector<Spot>时,代码中的i == t会调用std::vector的默认相等运算符。该运算符会逐元素比较,要求Spot类型必须支持==运算,但你的Spot结构体未重载operator==,导致编译失败。 std::equal_to<void>的出现逻辑
Visual Studio编译器在处理std::vector的相等比较时,内部会使用C++14引入的透明比较器std::equal_to<void>,所以错误信息中会提及该类型,但本质问题还是Spot缺少相等运算符。
解决方案
方式一:为Spot重载operator==
直接为Spot添加相等判断逻辑,让std::vector的默认比较可以正常工作:
struct Spot { int x, y; bool operator==(const Spot& other) const { return x == other.x && y == other.y; } };
方式二:自定义isin函数的比较逻辑
如果不想修改Spot结构体,可以针对std::vector<Spot>特化isin函数,或者添加比较器参数实现通用逻辑:
特化版本
template <> bool isin(std::vector<Spot> i, const std::vector<std::vector<Spot>>& vec) { for (const auto& t : vec) { if (i.size() == t.size() && i[0].x == t[0].x && i[0].y == t[0].y && i[1].x == t[1].x && i[1].y == t[1].y) { return true; } } return false; }
通用比较器版本
template <typename T, typename Compare = std::equal_to<T>> bool isin(T i, const std::vector<T>& vec, Compare comp = Compare{}) { for (const T& t : vec) { if (comp(i, t)) return true; } return false; } // 调用时传入自定义比较逻辑 if (!isin({ arr[i], arr[j] }, n, [](const std::vector<Spot>& a, const std::vector<Spot>& b) { return a.size() == b.size() && a[0].x == b[0].x && a[0].y == b[0].y && a[1].x == b[1].x && a[1].y == b[1].y; }))
内容的提问来源于stack exchange,提问作者jg1121
相关产品推荐
相关产品推荐

