CRTP 基私有构造函数和派生友元类使用 C++17 和统一初始化导致编译错误

bie*_*000 4 c++ crtp c++11 c++17

我有以下代码:

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();
} 
Run Code Online (Sandbox Code Playgroud)

由于某种原因,当使用 C++17 时,由于“x”变量的“不可编译”初始化,编译失败。编译器说:

Base::Base() [with T = Derived]' 在此上下文中是私有的

但正如您所看到的,下面我创建了一个相同类型的对象,但这次我没有使用统一初始化。x1 变量可以使用 C++11 或 C++17 标准进行编译,但 'x' 变量只能在 C++11 模式下编译。这是为什么?标准发生了什么变化导致了这个问题?

编译器浏览器

Hol*_*Cat 5

从 C++17 开始显然Derived是聚合,Derived{}聚合初始化也是如此。( C++17 之前的聚合中不允许基类,现在允许公共非虚拟基。)

含义Base::Base()由调用者 ( ) 直接调用main(),而不是Derived.

解决方案是添加Derived() {}toDerived以阻止其成为聚合。