【问题标题】:emplace and unordered_map<?, std::array<?, N>>emplace 和 unordered_map<?, std::array<?, N>>
【发布时间】:2015-10-06 14:08:33
【问题描述】:

我有一个std::unordered_map&lt;string, std::array&lt;int, 2&gt;&gt;emplace将值写入映射的语法是什么?

unordered_map<string, array<int, 2>> contig_sizes;
string key{"key"};
array<int, 2> value{1, 2};

// OK ---1
contig_sizes.emplace(key, value);

// OK --- 2
contig_sizes.emplace(key, std::array<int, 2>{1, 2});

// compile error --3
//contig_sizes.emplace(key, {{1,2}});

// OK --4 (Nathan Oliver)
// Very inefficient results in two!!! extra copy c'tor
contig_sizes.insert({key, {1,2}});

// OK --5
// One extra move c'tor followed by one extra copy c'tor
contig_sizes.insert({key, std::array<int, 2>{1,2}});

// OK --6 
// Two extra move constructors
contig_sizes.insert(pair<const string, array<int, 2>>{key, array<int, 2>{1, 2}});

我正在使用 clang++ -c -x c++ -std=c++14 和 clang 3.6.0

我测试了http://ideone.com/pp72yR中的代码

附录: (4) 由 Nathan Oliver 在下面的答案中提出

【问题讨论】:

  • emplace 需要推断其参数的类型,但{{1,2}} 没有类型(它不是表达式)。

标签: c++ dictionary unordered-map stdarray emplace


【解决方案1】:

来自cppreference std::unordered_map::emplace 被声明为

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

所以它试图推断传递给它的类型。这将发挥作用 [temp.deduct.type] § 14.8.2.5

- 一个函数参数,其相关参数是一个初始化列表 (8.5.4),但该参数没有指定从初始化列表推导的类型 (14.8.2.1)。 [ 例子:

template<class T> void g(T);  
g({1,2,3}); // error: no argument deduced for T

——结束示例]

因此无法推断出任何类型。

如果您想动态创建对象,那么您可以使用以下形式:

contig_sizes.emplace(key, std::array<int, 2>{1, 2});

或者我们可以创建一个typedef

typedef pair<const string, array<my_class, 2>> pair_type;

然后我们可以有

contig_sizes.emplace(pair_type{key, {1, 2}});

您还可以使用std::unordered_map::insert,它采用可以从花括号初始化列表构造的键/值的pair

contig_sizes.insert({key, {1, 2}});

【讨论】:

  • unordered_map::insert 导致两个额外的复制 c'tors (ideone.com/pp72yR)。要将其减少到仅移动 c'tors,您似乎需要这种可怕的语法:contig_sizes.insert(pair&lt;const string, array&lt;int, 2&gt;&gt;{key, array&lt;int, 2&gt;{1, 2}});
  • @LeoGoodstadt 这可以通过简单的typedef 来解决。 typedef pair&lt;const string, array&lt;my_class, 2&gt;&gt; pair_type; 然后contig_sizes.insert(pair_type{key, {1, 2}});
  • @LeoGoodstadt 我更新了答案,让emplace() 使用起来很容易。
  • 我无法用typedef 删除多余的副本。出于某种原因,我仍然需要contig_sizes.emplace(pair_type{key, std::array&lt;my_class, 2&gt;{1, 2}});。 :-( 还是不如我原来的contig_sizes.emplace(key, std::array&lt;int, 2&gt;{1, 2});效率高!!!我还不如typedef值类型:typedef std::array&lt;int, 2&gt;{1, 2} value_type;contig_sizes.emplace(key, value_type{1,2});
  • @LeoGoodstadt 你试过contig_sizes.emplace(pair_type{key, {1, 2}});吗?
猜你喜欢
  • 2014-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多