11

I thought maps and reference_wrappers would go easy but I tripped over something weird:

#include <map>
#include <functional>

int main(void) {
    std::map<int, std::reference_wrapper<const int>> mb;
    const int a = 5;
    mb[0] = std::cref(a);
}

This piece of code gives me the following compiler error:

In file included from c:/MinGW/x86_64-w64-mingw32/include/c++/bits/stl_map.h:63:0,
                 from c:/MinGW/x86_64-w64-mingw32/include/c++/map:61,
                 from ../test/main.cpp:9:
c:/MinGW/x86_64-w64-mingw32/include/c++/tuple: In instantiation of 'std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {int&&}; long long unsigned int ..._Indexes1 = {0ull}; _Args2 = {}; long long unsigned int ..._Indexes2 = {}; _T1 = const int; _T2 = std::reference_wrapper<const int>]':
c:/MinGW/x86_64-w64-mingw32/include/c++/tuple:1083:63:   required from 'std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {int&&}; _Args2 = {}; _T1 = const int; _T2 = std::reference_wrapper<const int>]'
c:/MinGW/x86_64-w64-mingw32/include/c++/ext/new_allocator.h:120:4:   required from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const int, std::reference_wrapper<const int> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const int, std::reference_wrapper<const int> > >]'
c:/MinGW/x86_64-w64-mingw32/include/c++/bits/alloc_traits.h:253:4:   required from 'static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::pair<const int, std::reference_wrapper<const int> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const int, std::reference_wrapper<const int> > > >; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]'
c:/MinGW/x86_64-w64-mingw32/include/c++/bits/alloc_traits.h:399:57:   required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::pair<const int, std::reference_wrapper<const int> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const int, std::reference_wrapper<const int> > > >; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]'
c:/MinGW/x86_64-w64-mingw32/include/c++/bits/stl_tree.h:423:42:   required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Key = int; _Val = std::pair<const int, std::reference_wrapper<const int> >; _KeyOfValue = std::_Select1st<std::pair<const int, std::reference_wrapper<const int> > >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::reference_wrapper<const int> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const int, std::reference_wrapper<const int> > >*]'
c:/MinGW/x86_64-w64-mingw32/include/c++/bits/stl_tree.h:1789:64:   required from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>}; _Key = int; _Val = std::pair<const int, std::reference_wrapper<const int> >; _KeyOfValue = std::_Select1st<std::pair<const int, std::reference_wrapper<const int> > >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::reference_wrapper<const int> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const int, std::reference_wrapper<const int> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const int, std::reference_wrapper<const int> > >]'
c:/MinGW/x86_64-w64-mingw32/include/c++/bits/stl_map.h:519:8:   required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = int; _Tp = std::reference_wrapper<const int>; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::reference_wrapper<const int> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::reference_wrapper<const int>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]'
../test/main.cpp:20:6:   required from here
c:/MinGW/x86_64-w64-mingw32/include/c++/tuple:1094:70: error: no matching function for call to 'std::reference_wrapper<const int>::reference_wrapper()'
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                      ^
c:/MinGW/x86_64-w64-mingw32/include/c++/tuple:1094:70: note: candidates are:
In file included from ../test/main.cpp:10:0:
c:/MinGW/x86_64-w64-mingw32/include/c++/functional:413:7: note: std::reference_wrapper<_Tp>::reference_wrapper(const std::reference_wrapper<_Tp>&) [with _Tp = const int]
       reference_wrapper(const reference_wrapper<_Tp>& __inref) noexcept
       ^
c:/MinGW/x86_64-w64-mingw32/include/c++/functional:413:7: note:   candidate expects 1 argument, 0 provided
c:/MinGW/x86_64-w64-mingw32/include/c++/functional:407:7: note: std::reference_wrapper<_Tp>::reference_wrapper(_Tp&) [with _Tp = const int]
       reference_wrapper(_Tp& __indata) noexcept
       ^
c:/MinGW/x86_64-w64-mingw32/include/c++/functional:407:7: note:   candidate expects 1 argument, 0 provided

Am I doing something really, really stupid here that I should be aware of? Why isn't this little piece of code working straight forward?

1 Answer 1

22

The operator[] of an std::map<K, T> requires that T be default-constructible.

Use this instead:

m.emplace(0, std::cref(a));

In C++17, you can also use one of these:

m.try_emplace(0, std::cref(a));
m.insert_or_assign(0, std::cref(a));
Sign up to request clarification or add additional context in comments.

1 Comment

Where do you find "c++17" docs ? cant find anything about try_emplace / insert_or_assign

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.