Великие умы думают одинаково; v).Я представил отчет о дефектах и предложил изменить стандарт на эту тему.
Когда для инициализации объекта используется требование EmplaceConstructible (23.2.1 [container.requirements.general] / 13), происходит прямая инициализация.Инициализация агрегата или использование конструктора std :: initializer_list с помощью emplace требует присвоения имени инициализированному типу и перемещения временного.Это результат использования std :: allocator :: construct с использованием прямой инициализации, а не синтаксиса инициализации списка (иногда называемой «равномерной инициализацией»).
Изменение конструкции std :: allocator :: для использования списочной инициализациибудет, среди прочего, отдавать предпочтение перегрузкам конструктора std :: initializer_list, нарушая допустимый код неинтуитивным и нефиксированным способом - у emplace_back не будет никакого доступа к конструктору, прерванному std :: initializer_list, без существенной повторной реализации push_back.
std::vector<std::vector<int>> v;
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization
Предлагаемый компромисс - использовать SFINAE с std :: is_constructible, который проверяет, правильно ли сформирована прямая инициализация.Если is_constructible имеет значение false, то выбирается альтернативная перегрузка std :: allocator :: construct, которая использует инициализацию списка.Поскольку инициализация списка всегда выполняется при прямой инициализации, пользователь увидит диагностические сообщения, как если бы всегда использовалась инициализация списка (равномерная инициализация), поскольку перегрузка прямой инициализации не может быть неудачной.
Я могуувидеть два угловых случая, которые показывают пробелы в этой схеме.Это происходит, когда аргументы, предназначенные для std :: initializer_list, удовлетворяют конструктору, например, при попытке вставки-вставки значения {3, 4} в вышеприведенном примере.Обходной путь должен явно указать тип std :: initializer_list, как в v.emplace_back (std :: initializer_list (3, 4)).Поскольку это соответствует семантике, как если бы выводился std :: initializer_list, здесь, похоже, нет реальной проблемы.
Другой случай, когда аргументы, предназначенные для агрегатной инициализации, удовлетворяют конструктору.Поскольку агрегаты не могут иметь определяемые пользователем конструкторы, для этого требуется, чтобы первый нестатический элемент данных агрегата был неявно конвертируемым из типа агрегата, и чтобы в списке инициализатора был один элемент.Обходной путь должен предоставить инициализатор для второго участника.По-прежнему невозможно создать агрегат только с одним нестатическим элементом данных путем преобразования из типа, преобразуемого в собственный тип агрегата.Это похоже на приемлемо маленькое отверстие.