Why is this combination of move and value constructor ambigous for MSVC but not for Clang and GCC in C++17 and above

  c++, c++17, c++20, standards-compliance, visual-c++

I have the following code

struct R {
    int i_=8;
    R() = default;
    R(R const& o) = default;
    R(R&& o) = default; // comment out either of these to make MSVC happy
    R(int i) : i_(i) {} // or mark the templated cast operator in R explcit
    operator int() const { return i_; }
};
struct S {
    R i_;
    operator R() const { return i_; }
    operator int() const { return i_.i_; }
    template <typename T>
    operator T() const {
        return static_cast<T>(i_);
    }
};
int main() {
    S s;
    R r0(s);
    R r = static_cast<R>(s);
    float af[]={1,2,3};
    float f1 = af[s];
    float f2 = af[r];
}

which compiles fine on Clang and GCC for C++17 and C++20 (not for C++ < 17) but complains about

'R::R': ambiguous call to overloaded function
note: could be 'R::R(R &&)'
note: or       'R::R(int)'

in MSVC for all available standards.

I tried to find a difference in the language conformances by comparing MSVC, Clang and GCC and also tried /permissive- for MSVC but couldn’t find any explanation yet.

  • Who is right (any why) and
  • how can I make it compile for MSVC without giving up on the R&& and int i ctors in R or making the templated cast operator T() in R explicit?

(One goal is to be able to use both types as array indices.)

Here’s a rather crowded godbolt.

Source: Windows Questions C++

LEAVE A COMMENT