简体   繁体   中英

Inherited synthesized comparison operator produces warning/error: ISO C++20 considers use of overloaded operator '!='

In the following code snippet clang 11.0.1 generates a warning

template <class T>
struct iterator_facade
{
    template<class S>
    bool operator==(const S &other) const noexcept
    {
        return static_cast<const T &>(*this).equal_to(other);
    }
};

struct iterator : public iterator_facade<iterator>
{
    bool equal_to(const iterator &) const noexcept
    {
        return true;
    }
};

bool check(iterator a, iterator b)
{
    return a == b;
}

The code live: https://godbolt.org/z/65zWEq

source>:21:14: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'iterator' and 'iterator') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]
    return a == b;
           ~ ^  ~
<source>:5:7: note: ambiguity is between a regular call to this operator and a call with the argument order reversed
        bool operator==(const S &other) const noexcept
             ^

The code above compiles successfully with Visual C++ (VS 16.8.x) and with previous preview (VS 16.9.0 Preview 2). However, recently released VS 16.9.0 Preview 3 now produces error for this code snippet:

1>C:\MyProjects\test\test\source.cpp(21,16): error C2666: 'foo<bar>::operator ==': 2 overloads have similar conversions
1>C:\MyProjects\test\test\source.cpp(5,7): message : could be 'bool iterator_facade<iterator>::operator ==<bar>(const S &) noexcept const' [rewritten expression '!(x == y)']
1>        with
1>        [
1>            S=iterator
1>        ]
1>C:\MyProjects\test\test\source.cpp(5,7): message : or 'bool iterator_facade<iterator>::operator ==<iterator>(const S &) noexcept const' [synthesized expression '!(y == x)']
1>        with
1>        [
1>            S=iterator
1>        ]
1>C:\MyProjects\test\test\source.cpp(21,16): message : while trying to match the argument list '(iterator, iterator)'

Does it look like there is no compliant way to provide synthesized comparison operators for a derived class iterator with CRTP class iterator_facade ?

The issue is we have this comparison operator:

template<class T>
struct iterator_facade
{
    template <class S>
    bool operator==(const S &other) const noexcept;
};

So when we try to compare two iterator s, we have these two candidates:

bool operator==(iterator_facade<iterator> const&, iterator const&); // the member candidate
bool operator==(iterator const&, iterator_facade<iterator> const&); // the reversed member candidate

And the problem is that the member candidate is an exact match in the 2nd argument but a derived-to-base conversion in the first pair... and the reversed candidate is an exact match in the 1st argument but a derived-to-base conversion in the second. This means neither candidate is better than the other, and the two are ambiguous.

Now, since this library actually requires C++20 to begin with, this is kind of pointless. Just make iterator implement operator== on its own, this adds... nothing? I'm not sure what it adds anyway.

But if you really want to make it work, you would need to provide a second overload that takes two instances of derived. As in:

template <class T>
struct iterator_facade
{
    friend bool operator==(T const& a, T const& b) noexcept {
        return a.equal_to(b);
    }

    template <sentinel_for<T> S>
    bool operator==(S const& other) const noexcept;
};

The homogeneous operator will be a better match than the heterogeneous one, so the comparison will compile fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM