使用 std::generate 的随机 unordered_multimap

Posted

技术标签:

【中文标题】使用 std::generate 的随机 unordered_multimap【英文标题】:Random unordered_multimap using std::generate 【发布时间】:2019-01-30 13:02:52 【问题描述】:

我正在尝试使用以下代码生成大小为 10 的随机 unordered_multimap

#include <algorithm>
#include <unordered_map>
#include <cstdlib>

int main()

    auto m = std::unordered_multimap<int, int>(10);
    std::generate(
        m.begin(),
        m.end(),
        []()return std::pairstd::rand(),std::rand();
    );
 

但是编译不会报错

 In file included from /usr/include/c++/7/algorithm:62:0,
                 from main.cpp:2:
/usr/include/c++/7/bits/stl_algo.h: In instantiation of ‘void std::generate(_FIter, _FIter, _Generator) [with _FIter = std::__detail::_Node_iterator<std::pair<const int, int>, false, false>; _Generator = main()::<lambda()>]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',11)">main.cpp:11:5</span>:   required from here
/usr/include/c++/7/bits/stl_algo.h:4438:11: error: use of deleted function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(typename std::conditional, std::is_copy_assignable<_T2> > >::value, const std::pair<_T1, _T2>&, const std::__nonesuch_no_braces&>::type) [with _T1 = const int; _T2 = int; typename std::conditional, std::is_copy_assignable<_T2> > >::value, const std::pair<_T1, _T2>&, const std::__nonesuch_no_braces&>::type = const std::pair&]’
  *__first = __gen();
  ~~~~~~~~~^~~~~~~~~
In file included from /usr/include/c++/7/utility:70:0,
                 from /usr/include/c++/7/unordered_map:38,
                 from main.cpp:1:
/usr/include/c++/7/bits/stl_pair.h:378:7: note: declared here
       operator=(typename conditional<
       ^~~~~~~~

:是否可以使用std::generate 生成随机的unordered_multimap?如果没有,最好的方法是什么?

PS:我知道我应该使用std::default_random_engine 而不是std::rand,并且我在实际代码中这样做,这只是为了演示目的。

【问题讨论】:

可能不是std::default_random_engine,而是std::mt19937。一些实现在前面做了interesting choices... 即使编译,m 仍然是空容器,即 m.begin() 和 m.end() 之间没有任何内容。 10 在这种情况下是桶数。只需使用简单的 for 循环即可避免所有麻烦。 【参考方案1】:

您可以使用std::insert_iterator 类模板来实现您要查找的内容:

auto m = std::unordered_multimap<int, int>;

std::generate_n(std::insert_iterator(m, m.begin()),
     10, []() return std::pairstd::rand(),std::rand(); ); 

【讨论】:

std::inserter 也在这里编译。这两者有什么区别? @PrzemysławCzechowski 无,现在可以推断出模板参数。 It was convenient before that 好的,在std::inserter 示例中,填充集合是通过:std::fill_n(std::inserter(s, s.end()), 5, 2); 完成的。那么我应该使用容器的begin 还是end 呢? 是的,它只会节省打字。在 C++17 之前,类模板是最难键入的,因为每个人都会使用函数模板来创建类型(例如 std::back_inserterstd::back_insert_iterator)。使用类模板参数推导,这已经改变。我实际上建议使用std::inserter【参考方案2】:

您的代码无法与地图一起使用。

来自documentation for std::generate

Ret 类型必须使得ForwardIt 类型的对象可以被取消引用并分配一个Ret 类型的值。 ​

您不能分配地图项的键。容器“拥有”密钥。您只能分配映射的值。 This method of "setting each element" is simply unavailable for associative containers.

此外,您构建了一个unordered_multimap with bucket size 10, but no actual elements,因此您的范围无论如何都是空的(地图不是向量!)。

您可以使用std::inserter

#include <algorithm>
#include <iterator>
#include <unordered_map>
#include <cstdlib>

int main()

    std::unordered_multimap<int, int> m;
    std::generate_n(
        std::inserter(m, m.begin()),
        10,
        []() return std::pairstd::rand(), std::rand(); 
    );

...但是,老实说,只是循环执行此操作并继续前进。 ;)

#include <unordered_map>
#include <cstdlib>

int main()

    std::unordered_multimap<int, int> m;
    for (size_t i = 0; i < 10; i++)
        m.emplace(std::rand(), std::rand());

每个人都可以阅读。

【讨论】:

OP 到std::generate_n(std::inserter(m, m.begin()), 10, []()return std::pairstd::rand(),std::rand(););的地方并不远@ @Caleth 你是对的,但这不是可读或不具表现力的代码。

以上是关于使用 std::generate 的随机 unordered_multimap的主要内容,如果未能解决你的问题,请参考以下文章

使用步骤 c++ 构建向量

如何用Arduino uno r3给另一块板子烧录Bootloader

仅移动类型的 back_inserter

函数指针函数符与Lambda表达式

如何用Arduino uno r3给另一块板子烧录Bootloader

ESP8266 D1-UNO-R3开发板的初步测试