std :: map <> ::使用不可复制对象和统一初始化插入

mfo*_*ini 12 c++ movable noncopyable c++11

看看下面的代码:

#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
}
Run Code Online (Sandbox Code Playgroud)

在取消注释g ++ 4.7上的标记行时,编译此代码段失败.产生的错误表明non_copyable无法复制,但我预计它会被移动.

为什么插入std::pair使用统一初始化的构造失败但没有使用构造std::make_pair?两者都不应该产生可以成功移入地图的右值吗?

Ker*_* SB 18

[这是完全重写.我之前的回答与这个问题无关.]

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()}));
Run Code Online (Sandbox Code Playgroud)

现在list-initializer知道查找map_type::value_type构造函数,找到相关的可移动函数,结果是一个rvalue对,它绑定到函数的P&&-overload insert.

(另一种选择是使用emplace()piecewise_constructforward_as_tuple,虽然会得到很多更详细.)

我认为这里的道德是list-initializers寻找可行的重载 - 但他们必须知道要寻找什么!

  • 我想令人惊讶的是,`map`确实*没有'value_type &&`的`insert`重载,而`vector`则有. (6认同)