Random unordered_multimap using std::generate

219 Views Asked by At

I'm trying to generate a random unordered_multimap of size 10 using the following code:

#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::pair{std::rand(),std::rand()};}
    );
} 

But it won't compile with an error

 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<
       ^~~~~~~~

Q: Is it possible to generate a random unordered_multimap using std::generate? If not, what's the best way to do it?

PS: I know I should be using std::default_random_engine instead of std::rand, and I do in the real code, this is just for demonstrative purposes.

2

There are 2 best solutions below

4
On BEST ANSWER

You can use the std::insert_iterator class template to achieve what you're looking for:

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

std::generate_n(std::insert_iterator(m, m.begin()),
     10, [](){ return std::pair{std::rand(),std::rand()}; }); 
2
On

Your code can't work with a map.

From documentation for std::generate:

The type Ret must be such that an object of type ForwardIt can be dereferenced and assigned a value of type Ret. ​

You can't assign a map item's key. The container "owns" the key. You can only assign the mapped value. This method of "setting each element" is simply unavailable for associative containers.

Furthermore, you constructed an unordered_multimap with bucket size 10, but no actual elements, so your range is empty anyway (maps aren't vectors!).

You could do this with 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::pair{std::rand(), std::rand()}; }
    );
}

…but, honestly, just do this in a loop and move on. ;)

#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());
}

Everybody can read this.