【问题标题】:What are the restrictions on std::map<K, V>::mapped_type?std::map<K, V>::mapped_type 有什么限制?
【发布时间】:2015-07-10 17:50:16
【问题描述】:

考虑这段代码:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class Foo {
  public:
  Foo() {}
  virtual ~Foo() {}

  void DoFoo() { cout << "Foo" << endl; }

  Foo(const Foo&) = delete;
  void operator=(const Foo&) = delete;
};

int main() {
  map<string, Foo> m;
  m["Foo"].DoFoo();
}

g++ 和 clang++ 在使用早于 4.8 的 libstdc++ 版本时编译失败。 clang++ 吐出的确切错误信息是:

在 /usr/include/c++/4.6/iostream:39 包含的文件中:

在 /usr/include/c++/4.6/ostream:39 中包含的文件中:

在 /usr/include/c++/4.6/ios:40 包含的文件中:

在 /usr/include/c++/4.6/bits/char_traits.h:40 包含的文件中:

在 /usr/include/c++/4.6/bits/stl_algobase.h:65 包含的文件中:

/usr/include/c++/4.6/bits/stl_pair.h:121:35:错误:调用已删除 'Foo'的构造函数

: 第一个(std::forward<_u1>(__x)), 第二个(__y) { }

^~~~

/usr/include/c++/4.6/bits/stl_pair.h:267:14:注意:在实例化 函数模板特化 'std::pair, Foo>::pair, void>' 在这里请求

return __pair_type(std::forward<_t1>(__x), std::forward<_t2>(__y));

^

/usr/include/c++/4.6/bits/stl_map.h:467:29:注意:在实例化 函数模板特化 'std::make_pair, Foo>' 在这里请求

__i = insert(__i, std::make_pair(std::move(__k), mapped_type()));

^

21 : 注意: 在成员函数 'std::map, Foo, std::less >, std::allocator, Foo> > >::operator[]' 在这里请求

m["Foo"].DoFoo();

似乎std::pair 的构造函数正在尝试使用Foo 的复制构造函数,我想这很公平,因为Foo 没有声明移动构造函数。正如我所料,提供(默认)移动构造函数可以解决问题。

但是,当使用的 libstdc++ 版本为 4.8 或更高版本时,编译成功而无需定义移动构造函数。我相信编译器在这两种情况下都是相同的,只有libstdc++ 版本不同。 Foo(Foo&amp;&amp;) = delete; 在这种情况下也不会影响 clang 正确编译的能力。

我的问题有几个方面:

为什么旧版本的libstdc++ 需要用户提供移动构造函数才能使用它而不是复制构造函数?

较新版本的库有什么不同,允许它在没有任何移动/复制构造函数或operator= 的情况下创建新元素(根据operator[] 的合同)?

哪些实现符合要求?标准对std::map&lt;K, V&gt;::mapped_type 有什么看法(如果有的话)?

【问题讨论】:

  • 23.2.4.7 has The associative containers meet all the requirements of Allocator-aware containers (23.2.1), except that for map and multimap, the requirements placed on value_type in Table 96 apply instead to key_type and mapped_type. [ Note: For example, in some cases key_type and mapped_type are required to be CopyAssignable even though the associated value_type, pair&lt;const key_type, mapped_type&gt;, is not CopyAssignable. —end note ] 可能是导致问题的原因。
  • @CoryKramer 似乎正在使用最近的libstdc++,我知道它可以正常编译。
  • @NathanOliver 谢谢,我会试着去看看那里!注释指向较新版本的libstdc++ 没有标准那么严格,不是吗?

标签: c++ c++11 standards standard-library


【解决方案1】:

在 C++11 中,[map.access] 为:

T&amp; operator[](const key_type&amp; x);

1 效果:如果映射中没有与x 等效的键,则将value_type(x, T()) 插入映射中。

2 要求key_type 应为 CopyInsertable,mapped_type 应为 DefaultInsertable *这个。

3 返回:对 *this 中 x 对应的 mapped_type 的引用。

4 复杂度:对数。

mapped_typeoperator[] 的唯一要求是它是 DefaultInsertable(基本上是 DefaultConstructible)。如果库不支持不可复制的mapped_typeoperator[],那么这是一个错误。

【讨论】:

  • @TemplateRex 我正在尝试为此找到 gcc 错误,但找不到。它肯定会在 4.7.2 上失败。
  • 4.7.2 太旧了,有资格为旧车换现金
  • 太棒了,非常感谢。这正是我想要的。
  • 可能通过44436解决
猜你喜欢
  • 2019-07-30
  • 1970-01-01
  • 2019-10-10
  • 1970-01-01
  • 2011-04-21
  • 2021-04-25
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
相关资源
最近更新 更多