Когда инициализация aggregate допустима в C++11?
Допустим, у нас есть следующий код:
#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()};
}
Здесь я считаю, что struct A
не является агрегатом, поскольку он имеет как нетривиальные конструкторы, так и член std::string
, который, как я предполагаю, не является агрегатом. Это предположительно означает, что B
также не является агрегатом.
Однако я могу агрегировать инициализацию B. Кроме того, это можно сделать без вызова конструктора копирования или перемещения (например, C++0x GCC 4.5.1 on ideone).
Такое поведение кажется полезным. оптимизация, особенно для объединения больших типов стеков, которые не имеют дешевых ходов.
Мой вопрос: когда такой тип агрегатной инициализации допустим в C++0x?
Edit + follow up question:
DeadMG ниже ответил следующим образом:
Обратите внимание, что когда я изменяюЭто вообще не агрегатная инициализация, это равномерная инициализация, которая в основном в этом случае означает вызов конструктора, и отсутствие копирования или перемещения, вероятно, выполняется RVO и НРВО.
B
на следующее:
struct B
{
A a;
B(const A& a_) : a(a_) {}
B(A&& a_) : a(std::move(a_)) {}
};
Выполняется перемещение.
Итак, если это просто равномерная инициализация и просто вызов конструктора и ничего особенного не делать, то как я могу написать конструктор, который позволяет перемещение быть elided?
Или GCC просто не устраняет перемещение здесь, когда это допустимо, и если да, то есть ли компилятор и параметры оптимизации, которые будут устранять перемещение?
2 ответа:
Согласно новому стандарту, п. 8.5.1 (Aggretates), достаточно простой тип (например, отсутствие определяемых пользователем конструкторов) квалифицируется как агрегат . Для такого агрегата
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}};
Объект
x
строится со всеми соответствующими конструкторами, выполненными на месте. Нет карты или строки или MyClasses когда-нибудь скопированы или перемещены. Обратите внимание, что оба варианта в нижней части делают такая же вещь. Вы даже можете сделать копию MyClass и переместить конструкторы частными, если хотите.