Посмотрите на следующий код:
#include <utility>
#include <map>
// non-copyable but movable
struct non_copyable {
non_copyable() = default;
non_copyable(non_copyable&&) = default;
non_copyable& operator=(non_copyable&&) = default;
// you shall not copy
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
};
int main() {
std::map<int, non_copyable> map;
//map.insert({ 1, non_copyable() }); < FAILS
map.insert(std::make_pair(1, non_copyable()));
// ^ same and works
}
Компиляция этого фрагмента завершается неудачно при раскомментировании отмеченной строки в g ++ 4.7. Произошедшая ошибка указывает на то, что non_copyable
не может быть скопировано, но я ожидал, что это будет перемещено.
Почему вставка std::pair
построено с использованием одинаковой ошибки инициализации, но не с использованием std::make_pair
? Разве оба не должны давать значения, которые могут быть успешно перемещены на карту?
map
имеет два соответствующих insert
перегрузки:
insert(const value_type& value)
, а также
<template typename P> insert(P&& value)
,
Когда вы используете простой список-инициализатор map.insert({1, non_copyable()});
, все возможные перегрузки рассматриваются. Но только первый (тот, который принимает const value_type&
), поскольку другой не имеет смысла (нет никакого способа волшебным образом догадаться, что вы хотели создать пару). Первая перегрузка, конечно, не работает, так как ваш элемент не копируется.
Вы можете заставить работать вторую перегрузку, явно создав пару, либо make_pair
, как вы уже описали, или явно указав тип значения:
typedef std::map<int, non_copyable> map_type;
map_type m;
m.insert(map_type::value_type({1, non_copyable()}));
Теперь инициализатор списка знает, что нужно искать map_type::value_type
конструкторы, находит соответствующий подвижный, и в результате получается пара значений, которая связывается с P&&
перегрузка insert
функция.
(Другой вариант заключается в использовании emplace()
с piecewise_construct
а также forward_as_tuple
хотя это было бы намного более многословным.)
Я полагаю, что мораль здесь в том, что инициализаторы списков ищут жизнеспособные перегрузки — но они должны знать, что искать!
Других решений пока нет …