X
- это совокупность . Хотя конкретное определение агрегата изменилось в каждом стандарте, ваш тип является агрегатом во всех из них.
List-initialization для агрегата выполняет здесь агрегатную инициализацию. Здесь нет конструктора - нет авто-конструктора, нет синтезированного конструктора. Агрегированная инициализация не создает конструкторы и не проходит через этот механизм. Мы непосредственно инициализируем каждого члена класса из соответствующего инициализатора в braced-init-list . Это то, что делают и ваши y
, и ваши z
.
Теперь для второй части. Соответствующая часть vector
выглядит так:
template <typename T>
struct vector {
void push_back(T&&);
template <typename... Args>
void emplace_back(Args&&...);
};
A braced-init-list , как и {99, "yo"}
, не имеет типа. И вы не можете вывести тип для этого. Они могут быть использованы только в определенных обстоятельствах. push_back({99, "yo"})
отлично работает, потому что push_back
занимает X&&
- это не шаблон функции - и мы знаем, как выполнить эту инициализацию.
Но emplace_back()
- это шаблон функции - он должен вывести Args...
из типов своих аргументов. Но у нас нет типа, нечего выводить! Здесь есть некоторые исключения (в частности, std::initializer_list<T>
может быть выведено), но здесь мы застряли. Вам нужно будет написать emplace_back(X{99, "yo"})
- что создает X
на стороне вызывающего.
Аналогично, emplace_back(99, "yo")
не работает, потому что emplace
использует ()
s для инициализации, но вы не можете ()
-инициализировать агрегат. У него нет конструктора!