Вставьте инициализированную в списке пару в std::map
Я пытаюсь вставить в карту только подвижный тип. У меня есть следующий кусок кода:
#include <map>
class Moveable
{
public:
Moveable() = default;
Moveable(const Moveable&) = delete;
Moveable(Moveable&&) = default;
Moveable& operator=(const Moveable&) = delete;
Moveable& operator=(Moveable&&) = default;
};
int main() {
std::map<int,Moveable> my_map;
Moveable my_moveable_1, my_moveable_2, my_moveable_3;
my_map.insert(std::pair<int,Moveable>{1, std::move(my_moveable_1)}); // (1)
my_map.insert(std::make_pair(2, std::move(my_moveable_2))); // (2)
my_map.insert({3, std::move(my_moveable_3)}); // (3)
return 0;
}
Что происходит, так это то, что с использованием VisualC++ строки 1,2 и 3 компилируются. В clang и gcc только 1 и 2 компилируются, а строка 3 выдает ошибку (использование конструктора удаленной копии).
Вопрос: Какой компилятор прав и почему?
Попробуй здесь: rextester
2 ответа
std::map::insert
имеет (среди прочих) следующие перегрузки:
// 1.
std::pair<iterator,bool> insert( const value_type& value );
// 2. (since C++11)
template< class P >
std::pair<iterator,bool> insert( P&& value );
// 3. (since C++17)
std::pair<iterator,bool> insert( value_type&& value );
Первая перегрузка, очевидно, не может использоваться с типами только для перемещения. Но вторая перегрузка, хотя и доступна в C++11, здесь не работает с фигурными скобками, потому что вывод фигурных аргументов шаблона не происходит с фигурными скобками (по крайней мере, в C++11, не уверенный в более поздних стандартах).
Ваш первый и второй вызов insert
работать в C++ 11 или более поздней версии, потому что компилятор знает тип, но третий не работает.
C++17 добавляет еще одну перегрузку, которая работает с фигурными скобками и только для перемещения типов. Теперь о том, почему он работает с определенными компиляторами, а не с другими, это, скорее всего, связано с различиями в уровне поддержки C++17 или флагами компилятора.
ОБНОВЛЕНИЕ: просто чтобы сделать это до боли очевидным: с помощью скобок я имею в виду использование только скобок (агрегатная инициализация или неявный вызов конструктора), т.е. insert({k,v})
не insert(pair<K,V>{k,v})
, В последнем случае тип известен, и шаблонная перегрузка может быть выбрана даже в C++11.
Я тестировал ваш код с помощью g++ 7.3, и он компилируется без ошибок!
С clang++ 5.0.1 он не компилируется.
Я думаю, что вы используете функцию C++20, поэтому поддержка еще не готова для всех компиляторов.