std::make_pair(...)
и std::move(std::make_pair(...))
- оба выражения rvalue (первый - это prvalue, второй - xvalue). Так как emplace
выполняет пересылку ссылок, оба выводятся как один и тот же тип, поэтому std::move
в этом случае является избыточным, но в общем случае избыточный std::move
может блокировать копирование.
m.emplace(1, std::make_pair(t1, t2));
эквивалентно:
auto&& arg = std::make_pair(t1, t2);
std::pair<const int, std::pair<T, T>> e(1, std::forward<std::pair<T, T>>(arg));
, который выполняет следующую инициализацию значения карте элемента:
auto&& arg = std::make_pair(t1, t2);
std::pair<T, T> p(std::forward<std::pair<T, T>>(arg));
Заметим, что это отличается от:
std::pair<T, T> p(t1, t2);
Форма r сначала создает пару prvalue (делает копии t1
и t2
), который затем перемещается из (перемещает как скопированные t1
, так и t2
в p
). Копирование отсутствует.
Последний использует t1
и t2
для инициализации как T
s, хранящихся в паре.
Чтобы избежать ненужного перемещения в результате первого синтаксиса, вместо этого можно использовать кусочно конструкцию:
m.emplace(std::piecewise_construct
, std::forward_as_tuple(1)
, std::forward_as_tuple(t1, t2));
, что будет эквивалентно:
auto&& arg = std::tuple<T&, T&>(t1, t2);
std::pair<T, T> p(std::get<0>(std::forward<std::tuple<T&, T&>>(arg))
, std::get<1>(std::forward<std::tuple<T&, T&>>(arg)));
, который будет инициализировать элементы пары от ссылочных членов, связанных с оригиналом t1
и t2
.
Здесь задействованы две 'std :: pair'. –