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

Viewed 142

I have the following code

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

bool operator==(R const& l, int r) {
    return true;
}
bool operator==(S const& l, int r) {
    return true;
}

int main() {
    return S() == 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.

Why does the expression static_cast<T>(1) - 1 result in a compiler error when compiled in an unevaluated context but not when compiled in the methods body?

Who is right here and why?

Here's a godbolt.

0 Answers
Related