std::map: Creating/replacing 不可默认构造的元素

std::map: Creating/replacing an element when it is not default-constructible

假设您有一个 class 不是默认构造的。

class A {
  private:
    int a;
  public:
    A() = delete;
    A(int a0) : a(a0) {}
};

现在,我们有一些映射 Int --> A,std::map<int, A> mapping。假设我们要为某个键 0 创建一个新映射,如果该键存在,我们要替换旧值。默认构造的 classes 的方法是这样的:

mapping[0] = A(4);

然而,这对于 class A 将失败,因为 operator[] 首先构造 A 的默认实例,然后才会分配 A(4) 的值。一般来说(即非默认构造的 classes)这样做的一种方法是:

auto it = mapping.find(0);
if (it == mapping.end()) {
  mapping.insert(0, A(4));
}
else {
  it->second = A(4);
}

我的问题是:这真的是 (C++) 预期的方式吗?我觉得这不对;作为一名程序员,我不想为这么少的东西写这么多代码。但似乎没有简单的出路:我查找了常见的映射方法(插入、放置、emplace_hint),如果密钥已经存在,它们都什么都不做。

I have looked up common map methods (insert, emplace, emplace_hint) and all of them do nothing if the key is already present.

C++17 已通过 std::map::insert_or_assign:

解决了这一点
template <class M>
pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);

If a key equivalent to k already exists in the container, assigns std::forward<M>(obj) to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value as if by insert, constructing it from value_type(k, std::forward<M>(obj)).

这使得

auto it = mapping.find(0);
if (it == mapping.end()) {
  mapping.insert(0, A(4));
}
else {
  it->second = A(4);
}

看起来像

mapping.insert_or_assign(0, A(4));

full program demo