C++ STL set自定义比较器场景下VS2019编译报C2672错误排查
问题根本成因
s1 != s2 触发C2672的原因
该报错是VS2019 Debug编译模式下STL实现的已知模板推导缺陷:
- 当为set配置自定义类类型的比较器时,Debug模式会启用运行时安全检查逻辑。在实例化set的相等/不等比较逻辑时,STL内部会通过
_Equal_to适配器绑定自定义比较器做元素相等判断。 - 这套检查逻辑在推导比较器
operator()的参数类型时存在漏洞,会错误地将set底层红黑树的节点存储类型当作元素类型,导致重载查找完全失败,抛出首个来自xutility的C2672报错,提示operator __surrogate_func找不到匹配重载。 - 移除
s1 != s2语句后,编译器不需要实例化这套相等比较逻辑,因此不会触发该缺陷;切到Release编译模式时,因为默认关闭这套安全检查,也不会出现相同报错。
set_difference 触发相同C2672的原因
该报错和上述STL缺陷无关,是算法调用方式不匹配导致的:
set_difference的默认重载会使用std::less<P>作为统一比较规则,要求元素类型实现operator<方法来支持大小比对。- 你定义的
P结构体没有实现这个运算符,因此在重载查找时找不到匹配的函数,触发和之前完全相同的C2672报错。之前补充<algorithm>和<iterator>头文件只能解决算法函数的声明可见性问题,无法解决比较逻辑不匹配的核心矛盾。
可落地修复方案
修复集合不等比较的编译错误
三选一即可规避VS2019的模板推导缺陷:
- 将自定义比较器的声明关键字从
class改为struct,利用struct默认public访问的特性,绕开类型推导的漏洞。 - 在比较器类的public区域显式声明默认构造函数:
PSortingCriterion() = default; - 在比较器类的public区域添加透明比较类型别名:
using is_transparent = void;,告知STL适配器跳过存在缺陷的类型推导检查。
修复set_difference的编译错误
调用算法时显式传入与set内部规则完全一致的比较器实例,修改后的调用代码为:
set_difference( s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(diff, diff.begin()), PSortingCriterion{} // 显式传入自定义比较器,替代默认的less<P>规则 );
调整后算法会直接复用你定义的字符字段字典序比较逻辑,不需要依赖P类型的operator<,即可正确完成两个集合的差集计算。
内容的提问来源于stack exchange,提问作者Woody20。
相关产品推荐
相关产品推荐

