c++ 运算符==和运算符!=打破一些概念

but5z9lq  于 2023-05-19  发布在  其他
关注(0)|答案(1)|浏览(164)

升级到最新的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 version 17.6 does not like next line
    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>;
  };
  
// ok in GCC, Clang and Visual Studio before version 17.6
static_assert( comparable<A, B> );

GCC和Clang接受该示例,但不接受最新的Visual Studio,它会打印错误:

<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)'

在线演示:https://gcc.godbolt.org/z/evTfofq3d
这是新的Visual Studio编译器中的一个错误,还是相反,其他人错了?

4sup72z8

4sup72z81#

这里潜在的问题似乎与不同的编译器如何处理ADL(参数相关查找)和重载解析有关。
您提供的重载将在多个操作符声明可见的上下文中使用(由于ADL规则)。有趣的是,这会导致歧义,不同的编译器会以不同的方式解决。
在匹配运算符时,版本17.6似乎比GCC、Clang和Visual Studio的早期版本有更严格的解释!=和operator==。
所以,回答你的问题,错误可能是由于编译器错误,或者它可能是由于更严格的遵守C++标准在较新版本的Visual Studio。如果没有std::ranges::range的完整规范以及它如何与operator交互,很难确定!=和operator==。
也许,一个可能的解决方法是定义操作符!=在运算符==方面对于A和B:

struct A {
    friend bool operator ==( const A &, const A & ) = default;
    friend bool operator !=( const A &a, const A &b ) { return !(a == b); }
};

struct B {
    friend bool operator ==( const B &, const B & ) = default;
    friend bool operator ==( const B &, const A & ) { return false; }
    friend bool operator !=( const B &b, const A &a ) { return !(b == a); }
};
``

相关问题