聚合初始化在C++11中何时有效

When is aggregate initialisation valid in C++11?

本文关键字:何时 有效 C++11 初始化      更新时间:2023-10-16

假设我们有以下代码:

#include <iostream>
#include <string>
struct A
{
  A() {}
  A(const A&) { std::cout << "Copy" << std::endl; }
  A(A&&) { std::cout << "Move" << std::endl; }
  std::string s;
};
struct B
{
  A a;
};
int main()
{
  B{A()};
}

在这里,我认为结构A不是聚合,因为它既有非平凡的构造函数,也有一个std::string成员,我认为它不是聚合。这大概意味着B也不是一个集合。

然而,我可以聚合初始化B。此外,这可以在不调用复制或移动构造函数的情况下完成(例如,ideone上的C++0x GCC 4.5.1)。

这种行为似乎是一种有用的优化,特别是对于将没有廉价移动的大型堆栈类型组合在一起而言。

我的问题是:在C++0x下,这种聚合初始化什么时候有效?

编辑+跟进问题:

下面的DeadMG回答如下:

这根本不是聚合初始化,而是统一初始化,在这种情况下,这基本上意味着调用构造函数,而无复制或移动可能是由RVO和NRVO完成的。

请注意,当我将B更改为以下内容时:

struct B
{
  A a;
  B(const A& a_) : a(a_) {}
  B(A&& a_) : a(std::move(a_)) {}
};

执行移动。

所以,如果这只是一个统一的初始化,只是调用构造函数,不做任何特殊的事情,那么我该如何编写一个允许删除移动的构造函数呢?

或者GCC只是在有效的情况下不删除移动,如果是,是否有编译器和优化设置可以删除移动?

根据新标准第8.5.1条(聚合),足够简单的类型(例如,没有用户定义的构造函数)符合聚合的条件。对于这样的聚合Foo,写入Foo x{a, b, ... };将根据列表项构造成员。

简单示例:

struct A
{
  std::unordered_map<int, int> a;
  std::string b;
  std::array<int,4> c;
  MyClass d; // Only constructor is MyClass(int, int)
};
// Usage:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, MyClass(4,4)};
// Alternative:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, {4,4}};

对象CCD_ 7是用在适当位置执行的所有相关构造函数来构造的。任何地图、字符串或MyClasses都不会被复制或移动。请注意,底部的两个变体做的是相同的事情。如果您愿意,您甚至可以将MyClass的复制和移动构造函数设置为私有的。

这根本不是聚合初始化,而是统一初始化,在这种情况下,这基本上意味着调用构造函数,而无复制或移动可能是由RVO和NRVO完成的。