看看下面的代码:
#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构造的?两者都不应该产生可以成功地移动到地图中的值吗?
解决方法
[这是一个完整的重写.我以前的答复与这个问题无关.]
该地图有两个相关的插入重载:
> insert(const value_type& value),和
>< template typename P>插入(P&& value).
当您使用简单的list-initializer 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构造函数,找到相关的可移动的构造函数,结果是一个rvalue对,它绑定到插入函数的P& -overload.
(另一个选择是使用片段式构造和forward_as_tuple来使用emplace(),尽管这样会更详细一些.)
我认为这里的道德是列表初始化器寻找可行的重载 – 但是他们必须知道要寻找的内容!