VS2022 17.6中同时定义==与!=运算符导致concept不满足,是编译器Bug吗?
问题分析与解答
问题背景
升级至Visual Studio 2022 17.6版本后,自定义视图不再被识别为std::ranges::range,经排查问题出在视图迭代器同时定义了operator ==和operator !=运算符。
最小复现示例
struct A { friend bool operator ==( const A &, const A & ) = default; }; struct B { friend bool operator ==( const B &, const B & ) = default; friend bool operator ==( const B &, const A & ) { return false; } // Visual Studio 2022 17.6版本对该行报错 friend bool operator !=( const B &, const A & ) { return true; } }; template< class T, class U > concept comparable = requires(const std::remove_reference_t<T>& t, const std::remove_reference_t<U>& u) { { t == u } -> std::same_as<bool>; { t != u } -> std::same_as<bool>; { u == t } -> std::same_as<bool>; { u != t } -> std::same_as<bool>; }; // GCC、Clang及17.6之前的Visual Studio可正常通过 static_assert( comparable<A, B> );
编译器表现差异
上述代码可在GCC、Clang以及17.6版本之前的Visual Studio中正常编译,但在Visual Studio 2022 17.6中会触发以下错误:
<source>(25): error C2607: static assertion failed <source>(25): note: the concept 'comparable<A,B>' evaluated to false <source>(18): note: 'bool operator ==(const B &,const A &)': rewritten candidate function was excluded from overload resolution because a corresponding operator!= declared in the same scope <source>(4): note: could be 'bool operator ==(const A &,const A &)' [found using argument-dependent lookup] <source>(8): note: or 'bool operator ==(const B &,const B &)' [found using argument-dependent lookup] <source>(9): note: or 'bool operator ==(const B &,const A &)' [found using argument-dependent lookup] <source>(4): note: or 'bool operator ==(const A &,const A &)' [synthesized expression 'y == x'] <source>(8): note: or 'bool operator ==(const B &,const B &)' [synthesized expression 'y == x'] <source>(9): note: or 'bool operator ==(const B &,const A &)' [synthesized expression 'y == x'] <source>(18): note: 'bool operator ==(const B &,const A &)': rewritten candidate function was excluded from overload resolution because a corresponding operator!= declared in the same scope <source>(18): note: while trying to match the argument list '(const A, const B)'
问题本质
这并非Visual Studio 17.6的Bug,恰恰相反,是该版本的编译器实现更严格遵循了C++标准的要求,而GCC、Clang及旧版VS的实现存在疏漏。
根据C++标准规则:如果为某对类型(比如B和A)显式声明了operator!=,那么通过反向重载重写生成的对应operator==(比如A==B,从B==A重写而来)会被排除在重载解析之外。
在代码中,B与A的operator!=是显式定义的,这导致A==B无法通过B==A的重载自动生成,而代码中又没有显式声明A==B的重载函数,因此comparable<A,B>概念中要求的u == t(即const A& == const B&)条件无法满足,最终触发静态断言失败。
修复方案
有两种可行的修复方式:
- 显式添加反向
operator==重载:在struct A中添加friend bool operator==(const A&, const B&) { return false; },确保A==B有明确的重载实现。 - 删除显式的
operator!=:移除struct B中的operator!=(const B&, const A&),让编译器自动生成反向的!=和==重载,既符合标准,也能减少冗余代码。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

