I've encountered a problem with implicit conversion in C++. The following is a minimal example:
struct A {
virtual void f()=0; // abstract
};
struct Ad : A {
virtual void f() {} // not abstract
};
struct B {
operator Ad () const { return Ad(); }
};
void test(A const &lhs) {}
int main()
{
B b;
test(b);
}
What I would like the compiler to do is: convert b to a variable of type Ad (using the conversion defined in B) and pass the result to test. However, the above code does not compile in GCC (with C++11 enabled), the result being Cannot allocate an object of abstract type 'A'.
Some things to note:
- Clang compiles this.
- If you make A non-abstract by changing
f()=0;
tof() {}
, the code works just fine. - The compiler does find the conversion operator (as indicated by 2), but it doesn't do what I'd like it to do.
(All quotes from N4140, the C++14 FD)
TL;DR: The code is well-formed, this is (or was) a GCC bug.
The rules for reference initialization are covered in [dcl.init.ref]/5. I'll first show you the bullet that doesn't cover it - if you want to skip that go straight to the third quote.
And reference-compability is defined in [dcl.init.ref]/41.
Now consider the linked 13.3.1.6:
As you can see, your conversion function isn't a candidate after this paragraph. Thus the next bullet in [dcl.init]/5 is applicable:
Note that the phrase "the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed" may imply that as
is ill-formed, the program is ill-formed. I believe this to be a defect or vagueness in the wording though, and not the reason that GCC does not accept the code. Assuredly the wording solely aims at the initialization itself, not the fact that a most-derived object of type
T1
(akaA
) can be created in the first place.Finally 13.3.1.4 accepts our conversion function:
Now the last question is whether in
ref
is bound directly. And it is.Thus the original parameter reference binds directly, and no most-derived object of type
A
must be created.What GCC presumably thinks is that a temporary of type
A
must be initialized and the reference be bound to that temporary. Or it pedantically follows the above defected wording, which is very unlikely.1)