The following program:
#include <iostream>
struct A
{
A() { std::cout << "A()\n"; }
A(int) { std::cout << "A(int)\n"; }
};
struct C {
operator int() {
std::cout << "operator int\n";
return 42;
}
operator A() {
std::cout << "operator A\n";
return A();
}
};
int main() {
auto a = A{C{}};
};
compiles and, when run, prints:
operator A
A()
See Godbolt link.
This shows that the move constructor of A
was selected to perform the initialization, with C::operator A()
being invoked to convert C
into the type that the move constructor expects.
Alternatively, the A::A(int)
constructor could have been selected, with C::operator int()
being invoked. But A::A(int)
loses overload resolution, apparently.
Why does this happen? I am not able to see any rule in the standard that explains why the move constructor of A
wins the overload resolution.
(This question is inspired by this answer; I could not understand why the code in that answer works.)
It appears that both GCC and Clang implemented a fix for CWG2327 by directly considering conversion functions to cv T as candidates when initializing an object of type cv2 T, in addition to constructors.
When C::operator A()
is considered as a candidate itself, it is an exact match, and therefore prevails over the constructor call which requires a user-defined conversion.
That issue is still in drafting status, so you won't be finding this in the wording.
Notably both reject with -std=c++14
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With