Ответ 1
Для v.emplace_back({41,42});
см. как использовать std::vector:: emplace_back для vector < vector <int → ?
v.emplace_back(41,42);
не работает из-за некоторых правил в стандарте (некоторые мои замечания):
Таблица 101 - Дополнительные операции контейнера последовательности
Выражение:
a.emplace_back(args)
Тип возврата:
void
Операционная семантика:
Добавляет объект типаT
, построенный с помощьюstd::forward<Args>(args)...
.
Требуется: T EmplaceConstructible вX
отargs
. Дляvector
T также должен быть MoveInsertable в X.
Для типа EmplaceConstructible
,
§ 23.2.1.13
- T EmplaceConstructible в X из args, для ноль или более аргументов args означает, что следующее выражение хорошо сформировано:
allocator_traits<A>::construct(m, p, args);
std::allocator_traits::construct()
в свою очередь делает (если возможно) a.construct(p, std::forward<Args>(args)...)
(где a
есть m
в выражении EmplaceConstructible).
a.construct()
здесь std::allocator::construct()
, который вызывает ::new((void *)p) U(std::forward<Args>(args)...)
. Это то, что вызывает ошибку компиляции.
U(std::forward<Args>(args)...)
(обратите внимание на использование прямой инициализации) найдет конструктор U
, который примет перенаправленные аргументы. Однако в вашем случае my_pair
является агрегированным типом, который может быть инициализирован только с помощью синтаксиса с принудительной инициализацией (агрегатная инициализация).
v.emplace_back(my_pair{41,42});
работает, потому что он вызывает либо неявно сгенерированный конструктор копии по умолчанию, либо перемещает конструктор (обратите внимание, что эти два не всегда могут быть сгенерированы). Сначала создается временная my_pair
, которая проходит тот же процесс, что и процесс v.emplace_back(41,42);
, только аргумент представляет собой r-значение my_pair
.
ДОПОЛНИТЕЛЬНЫЙ 1:
И почему push_back (T & &) работает без добавления имени структуры?
Это из-за push_back
подписей. push_back()
не выводится, что означает, что при выполнении push_back({1, 2})
сначала создается и инициализируется временный объект с типом типа векторного элемента с помощью {1, 2}
. Тогда этот временный объект будет тем, который передается в push_back(T&&)
.
Должен ли я просто придерживаться push_back? Есть ли какая-нибудь причина использовать emplace_back (structname {1,2,3}) вместо push_back ({1,2,3}), потому что в любом случае вызовет push_back (T & &), и его легче набрать?
В принципе, функции emplace*
предназначены для оптимизации и устранения затрат на создание временных рядов и копирования или перемещения объектов построения при их вставке. Однако для случая совокупных типов данных, когда выполнение чего-то типа emplace_back(1, 2, 3)
невозможно, и единственный способ, которым вы могли их вставить, - создать временное копирование или перемещение, тогда, во всяком случае, предпочитайте более компактный синтаксис и идите для push_back({1,2,3})
, где он будет в основном иметь такую же производительность, как у emplace_back(structname{1,2,3})
.