Should this code fail to compile in C++17?
Solution 1:
clang is correct here. Here's a reduced example:
struct B {
protected:
B() { }
};
struct D : B { };
auto d = D{};
In C++14, D
is not an aggregate because it has a base class, so D{}
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D{}
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.