While answering another question, I noticed something peculiar about conversion operators when dealing with ref-qualifiers.
Consider the following code:
using P = std::unique_ptr<int>;
struct A {
P p;
operator P() && { return std::move(p); }
operator P const&() const& { return p; }
};
int main() {
A a;
P p;
p = std::move(a);
}
This does not compile because apparently there is ambiguity when selecting the correct operator overload (see the errors in the demo below). It works if I remove the const
qualifier on the second overload like this:
operator P const&() & { return p; }
Also, if instead of an assignment I simply construct a P
object, it also works:
P p = std::move(a);
However, this only happens for conversion operators. If instead I write a normal member function that does the exact same thing, it compiles just fine.
struct B {
P p;
P get() && { return std::move(p); }
P const& get() const& { return p; }
};
int main() {
B b;
P p;
p = std::move(b).get();
}
Why is that? What's so special about a conversion operator for these overloads to be ambiguous when they aren't on a normal member function?
Side note: if instead of std::unique_ptr<int>
, I use a custom non-copyable type, nothing changes.
struct P {
P() = default;
P(P const&) = delete;
P(P&&) = default;
P& operator=(P const&) = delete;
P& operator=(P&&) = default;
};
Other side note: for some reason, MSVC doesn't say there is an ambiguity, it just selects the wrong overload. Unless I use my custom non-copyable type, in which case it agrees the call is ambiguous. So I guess it has to do with std::unique_ptr::operator=
. Not too important, but if you have any idea why, I'd love to know.