'CRTP base private constructor and derived friend class cause compilation error using C++17 and uniform initialization

I've got the following code:

struct B
{
  B(int) {}
};

template <typename T>
class Base : public B
{
  friend T;
  Base() : B(1) {}
};

class Derived : public Base<Derived>
{
public:
    void do_sth() const {}
};

int main()
{
  auto x = Derived{}; //Compiles only when using C++11
  auto x1 = Derived(); //Compiles using C++17/20 flag
  x.do_sth();
  x1.do_sth();
} 

For some reason when using C++17 compilation fails due to 'non-compilable' initialization of 'x' variable. Compilator says that:

Base::Base() [with T = Derived]' is private within this context

but as you can see, below I'm creating an object of the same type but this time I'm not using uniform initialization. x1 variable can be compiled using both C++11 or C++17 standards, but the 'x' variable is compilable only in C++11 mode. Why is that? What has changed in the standard that causes this problem?

Compiler explorer



Solution 1:[1]

Apparently Derived is an aggregate since C++17, so Derived{} is an aggregate initialization. (Base classes weren't allowed in aggregates pre-C++17, now public non-virtual bases are allowed.)

Meaning Base::Base() is invoked directly by the caller (main()), rather than Derived.

The solution is to add Derived() {} to Derived to stop it from being an aggregate.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 HolyBlackCat