Search code examples
c++c++11referencereference-wrapper

unordered_map value assignation when value type is reference_wrapper


I am experimenting with std::reference_wrapper. I don't understand why the following does work with a std::vector but not for a std::unordered_map:

#include <functional>
#include <vector>
#include <unordered_map>

using namespace std;

int main()
{
  vector<vector<long>> x;

  vector<reference_wrapper<vector<vector<long>>>> y;
  y.push_back(ref(x)); // OK

  unordered_map<string, reference_wrapper<vector<vector<long>>>> m;
  m["lol"] = ref(x); // NOT OK
}

This is the compilation error I get

/usr/include/c++/7.2.0/tuple:1652:70: error: no matching function for call to ‘std::
reference_wrapper<std::vector<std::vector<long int> > >::reference_wrapper()’       
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                      ^
In file included from /usr/include/c++/7.2.0/bits/std_function.h:44:0,              
                 from /usr/include/c++/7.2.0/functional:58,                         
                 from test.cpp:1:         
/usr/include/c++/7.2.0/bits/refwrap.h:325:7: note: candidate: constexpr std::referen
ce_wrapper<_Tp>::reference_wrapper(const std::reference_wrapper<_Tp>&) [with _Tp = s
td::vector<std::vector<long int> >]       
       reference_wrapper(const reference_wrapper&) = default;                       
       ^~~~~~~~~~~~~~~~~
/usr/include/c++/7.2.0/bits/refwrap.h:325:7: note:   candidate expects 1 argument, 0
 provided            
/usr/include/c++/7.2.0/bits/refwrap.h:319:7: note: candidate: std::reference_wrapper
<_Tp>::reference_wrapper(_Tp&) [with _Tp = std::vector<std::vector<long int> >]     
       reference_wrapper(_Tp& __indata) noexcept                                    
       ^~~~~~~~~~~~~~~~~
/usr/include/c++/7.2.0/bits/refwrap.h:319:7: note:   candidate expects 1 argument, 0
 provided  

Can someone explain what I am doing wrong?


Solution

  • m["lol"] uses the unordered maps operator[]. That operator returns a reference to the item in the map. Which is problematic if there is no such item.

    To resolve that, it will default construct the item it's supposed to return. And here lies the problem, because std::reference_wrapper is not default constructible.

    To make the two examples more equivalent, you'd need to use std::unordered_map::insert or std::unordered_map::emplace.