聚合与非聚合结构/类

我试图了解聚合类/结构/联合是什么:这是来自 C++ 标准:

聚合是一个数组或类(第 9 条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等号初始化器(9.2),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),也没有虚函数(10.3)。

所以我写了这个来测试:

struct NonAggregate{
    virtual void f()const&{} // virtual member function makes the struct non-aggregate
};

struct Bar{}; // aggregate
struct X{}; // aggregate

struct Foo : Bar, X{
   // Foo() = default; // if un-comment out makes Foo non-aggregate
   Foo& operator =(Foo const&){return *this;} // ok
   ~Foo(){} // ok
   int x_ = 0; // has an initializer. ? still aggregate?
   Bar b_{}; // has an initializer. still aggregate?

private:
    static double constexpr pi_ = 3.14;
};

double constexpr Foo::pi_; // definition needed- (although it has an in-class intializer) if Foo::pi_ used outside of the class

int main(){

    std::cout << std::boolalpha << "Foo is an aggregate type: " << std::is_aggregate<Foo>::value << 'n';

}

输出是:

Foo is an aggregate type: true
  • 那么为什么如果我默认合成的默认构造函数Foo不再是聚合?只要我没有提供用户定义的?

  • 标准还说:no base classes (Clause 10)但是我的结构从两个聚合结构继承了乘法BarX但仍然是 n 聚合??!

  • 标准说:no brace-or-equal-initializers for non-static data members (9.2)但我有非静态数据成员的初始值设定项x_b_但编译器仍将其视为Foo聚合结构??谢谢!

*PS:我使用过 GCC 和 C++2a 标准

回答

什么是聚合和什么不是聚合的规则在各种标准版本中发生了很大变化。这个答案简要强调了与 OP 的三个问题相关的变化。有关更详尽的段落,请参阅例如The fickle aggregate,其中介绍了这些不同的规则以及正确的标准(版本)参考。


那么为什么如果我默认合成的默认构造函数 Foo 不再是一个聚合呢?只要我没有提供用户定义的?

在 C++11 到 C++17 中,要求读取“无用户提供”构造函数,只要它们在第一次声明时被定义为显式默认或显式删除,它仍然允许声明构造函数。

// Aggregate in C++11 through C++17. Not an aggregate in C++20.
struct A {
    A() = default;  // user-declared, but not user-provided
};

// Aggregate in C++11 through C++17. Not an aggregate in C++20.
struct B {
    B() = delete;  // user-declared, but not user-provided
};

// Never an aggregate.
struct C {
    C();  // user-declared & user-provided
};
C::C() = default;

从 C++20 开始,这个要求对“没有用户声明的构造函数”变得更加严格。


标准还说:没有基类(第 10 条),但我的结构从两个聚合结构 Bar 和 X 继承了乘法,但仍然是 n 聚合??!

这是 C++11 和 C++14 中的规则。从 C++17 开始,它更宽松:

1.4) 没有虚拟、私有或受保护的基类 ([class.mi])。


标准说:非静态数据成员(9.2)没有大括号或相等初始化器,但我有非静态数据成员 x_ 和 b_ 的初始化器,但编译器仍然将 Foo 视为聚合结构?谢谢!

此规则在 C++14 中被删除。


以上是聚合与非聚合结构/类的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>