Given the following conversion operators
struct A
{
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
};
struct B {};
I would expect the following conversions to be all valid, yet some give compile errors (live example):
A a;
A&& ar = std::move(a);
A& al = a;
const A& ac = a;
B&& bm(std::move(a)); // 1. OK
B&& bt(A{}); // 2. OK
B&& br(ar); // 3. error: no viable conversion from A to B
B& bl(al); // 4. OK
const B& bz(al); // 5. OK
const B& bc(ac); // 6. OK
B cm(std::move(a)); // 7. error: call to constructor of B ambiguous
B ct(A{}); // 8. error: call to constructor of B ambiguous
B cr(ar); // 9. OK
In particular, 1 appears to be identical to 3, and almost identical to 2 (similarly for 7 to 9, 8), yet behave differently.
Any explanation or workaround?
My motivation is Yet another 'any', where I eventually had to make all conversion operators explicit
to avoid problems with type traits like std::is_constructible
, std::is_convertible
, then I bumped into new problems.
EDIT Sorry, please ignore 3 and 9, my mistake (thanks Kerrek SB). Yet 7 and 8 remain as problems. Also, explicit
appears to be irrelevant after all, sorry again.
EDIT 2 Just noticed that
B cm = std::move(a);
B ct = A{};
are valid if the conversion operators are not explicit
. So that's where explicit
comes in: initially my samples used copy-initialization, and when I switched to explicit
I had to use direct-initialization. Then this problem came up (cases 7 and 8).