std :: map<> :: insert使用不可复制的对象和统一的初始化 [英] std::map<>::insert using non-copyable objects and uniform initialization
问题描述
请查看以下代码:
#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
无法复制,但我预计它会被移动。
Compiling this snippet fails when uncommenting the marked line on g++ 4.7. The error produced indicates that non_copyable
can't be copied, but I expected it to be moved.
为什么插入使用统一初始化失败而不是使用 std :: make_pair
构造的 std :: pair
?不是都应该产生可以成功地移动到地图的右值?
Why does inserting a std::pair
constructed using uniform initialization fail but not one constructed using std::make_pair
? Aren't both supposed to produce rvalues which can be successfully moved into the map?
推荐答案
[这是一个完全重写。 ]
[This is a complete rewrite. My earlier answer had nothing to do with the problem.]
映射
有两个相关的 insert
overloads:
The map
has two relevant insert
overloads:
-
insert(const value_type& value) / code>和
insert(const value_type& value)
, and
< template typename P&
<template typename P> insert(P&& value)
.
当您使用简单列表时, initializer map.insert({1,non_copyable()});
,会考虑所有可能的重载。但是只有第一个(找到 const value_type&
)被找到,因为另一个没有意义(没有办法魔法猜测你打算创建一个对)。第一个over load当然不工作,因为你的元素不可复制。
When you use the simple list-initializer map.insert({1, non_copyable()});
, all possible overloads are considered. But only the first one (the one taking const value_type&
) is found, since the other doesn't make sense (there's no way to magically guess that you meant to create a pair). The first overload doesn't work of course since your element isn't copyable.
你可以通过显式地创建对来使第二个重载工作, code> make_pair ,或者通过明确命名值类型:
You can make the second overload work by creating the pair explicitly, either with make_pair
, as you already described, or by naming the value type explicitly:
typedef std::map<int, non_copyable> map_type;
map_type m;
m.insert(map_type::value_type({1, non_copyable()}));
现在列表初始化器知道要查找 map_type :: value_type
构造函数,找到相关的mova ble类型,结果是一个右值对,它绑定到
function。 P&&
$ c> insert
Now the list-initializer knows to look for map_type::value_type
constructors, finds the relevant movable one, and the result is an rvalue pair which binds to the P&&
-overload of the insert
function.
(另一个选项是使用 emplace()
与 piecewise_construct
和 forward_as_tuple
,但会得到更多的冗长。)
(Another option is to use emplace()
with piecewise_construct
and forward_as_tuple
, though that would get a lot more verbose.)
我想这里的道德是list-initializers寻找可行的重载–但他们必须知道要找什么!
I suppose the moral here is that list-initializers look for viable overloads – but they have to know what to look for!
这篇关于std :: map<> :: insert使用不可复制的对象和统一的初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!