samedi 27 mars 2021

Why triggers this noexcept operator an "overloads have similar conversions" error for MSVC but not for Clang and GCC

I have the following code

template <typename V>
struct S {
    V i_;
    S() : i_(0) {}
    template<typename T>
    operator T() const noexcept
    (noexcept(static_cast<T>(i_) - 1)) // comment out this line to make it work in MSVC
    {
        return static_cast<T>(i_) - 1;
    }
};
struct R {
    int i_;
    R(int i) : i_(i) {}
    operator int() const { return i_; }
    int operator-(R const& o) const { return i_ - o.i_; }
};

bool operator==(R const& l, int r)
{
    return l.i_ == r;
}
bool operator==(S<int> l, int r)
{
    return static_cast<int>(l) == static_cast<int>(r);
}

int main() {
    return S<int>() == 3;
}

which compiles fine on Clang and GCC for C++11 and above but complains about

'R::operator -': 2 overloads have similar conversions
note: could be 'int R::operator -(const R &) const'
note: or       'built-in C++ operator-(int, int)'
note: while trying to match the argument list '(T, int)' with [ T=R ]

in MSVC.

What's puzzling me is that removing the noexcept operator on the template operator T() on struct S makes the error disappear. Its expression is the exact same as the one in the body of the method it marks noexcept and I'd expect that the method body would cause the same error but it doesn't. This makes me suspect that I don't understand the noexcept operator at all.

Who is right here and why?

Here's a godbolt.

Aucun commentaire:

Enregistrer un commentaire