std :: map<> :: insert使用不可复制的对象和统一的初始化 [英] std::map<>::insert using non-copyable objects and uniform initialization

查看:163
本文介绍了std :: map<> :: insert使用不可复制的对象和统一的初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请查看以下代码:

#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 over­load 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类型,结果是一个右值对,它绑定到 P&& $ c> insert function。

Now the list-initializer knows to look for map_type::value_type constructors, finds the relevant mova­ble 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&lt;&gt; :: insert使用不可复制的对象和统一的初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆