The example can be simplified by taking `enum` out of the picture
#include <iostream>
class A {
public:
A(int) {}
};
class B {
public:
B(int) {}
};
void foo(A&&) {
std::cout << "Overload A\n";
}
void foo(const B&) {
std::cout << "Overload B\n";
}
int main() {
foo(0);
}
it will still exhibit the same behavior, but now it is fully
"symmetrical" with regard to `A` and `B`.
Experimenting with the example shows that MSVC seems to over-prioritize
the existing rule that binding rvalue reference to an rvalue is better
than binding an lvalue reference
http://eel.is/c++draft/over.ics.rank#3.2.3
However, in this case the two conversion sequences are incomparable
because they involve _different_ user-defined conversions. (In order to
be comparable they should use the same user-defined conversion.) This is
what is supposed to be recognized as an ambiguity by the compiler
http://eel.is/c++draft/over.ics.rank#3.3
If we simplify the example to a mere
#include <iostream>
class A {
public:
A(int) {}
};
void foo(A&&) {
std::cout << "Overload rvalue\n";
}
void foo(const A&) {
std::cout << "Overload lvalue\n";
}
int main() {
foo(0);
}
both candidate paths will use the the same user-defined conversion. The
call is no longer ambiguous, since the above
"rvalue-is-better-than-lvalue" logic kicks in.
--
Best regards,
Andrey Tarasevich