I have two classes st
and foo
:
struct st {
st() = default;
st(const st&) {
std::cout << "copy ctor." << std::endl;
}
st(st&&) {
std::cout << "move ctor." << std::endl;
}
};
struct foo {
operator st&() & {
return s;
}
operator const st&() const& {
return s;
}
operator st&&() && {
return std::move(s);
}
operator const st&&() const&& {
return std::move(s);
}
st s;
};
When I run code like this:
st s = st(foo());
It calls the copy constructor of st
.
Why does it not call foo
's rvalue-reference-qualified conversion function and use st
's move constructor?
EDIT:
MSVC
can compile this, but GCC
and Clang
cannot.const & operator
, then MSVC
, GCC
, Clang
can compile.&& operator
, then MSVC
and GCC
can compile, but Clang
cannot.&& operator
and const && operator
, then MSVC
, GCC
, Clang
can compile.Calling the copy constructor is wrong. The compiler is not following the specification.
The call is ill-formed, because overload resolution should be ambiguous.
The problem is quite generally that if you have two viable overloads, in this case the constructors
st(const st&);
and
st(st&&);
and both overloads require a user-defined conversion sequence in the argument where both use a different conversion function or constructor, the two conversion sequences are always considered equally good. How good the standard conversion sequences and the reference binding involved are, is only considered if the two user-defined conversion sequences would use the same conversion operator or constructor.