简体   繁体   中英

Custom std::set as value type to unordered_map

Let the code speak it:

auto SetCompare = [](const string& a, const string& b)
{
    size_t L = a.length();
    size_t R = b.length();
    if (L == R) return (a < b);
    return L < R;
};

using MySet = std::set<string, decltype(SetCompare)>;

unordered_map<string, MySet> Map;

The insertion or access won't work:

Map["abc"];
Map["xyz"].insert("mapped to xyz");

// Insert TO set works
MySet mySet(SetCompare); // HINT
mySet.insert("x");
mySet.insert("abc");

// But not to the map!
Map.insert({"pqr", mySet});

At the HINTed location, I pass SetCompare lambda ( not just type ) to MySet 's constructor. The question is how to pass it to the "Value" type of unordered_map ?

EDIT (Compiler errors):

GCC C++17

In file included from /usr/include/c++/7/set:60:0,
                 from main.cpp:10:
/usr/include/c++/7/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree_key_compare<_Key_compare>::_Rb_tree_key_compare() [with _Key_compare = main()::<lambda(const string&, const string&)>]’:
/usr/include/c++/7/bits/stl_tree.h:688:4:   required from ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {char&&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const char; _T2 = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >]’
/usr/include/c++/7/tuple:1641:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {char&&}; _Args2 = {}; _T1 = const char; _T2 = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >]’
/usr/include/c++/7/ext/new_allocator.h:136:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _Tp = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >]’
/usr/include/c++/7/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _Tp = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >]’
/usr/include/c++/7/bits/hashtable_policy.h:2066:37:   required from ‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::__detail::_Hash_node<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >, false>]’
/usr/include/c++/7/bits/hashtable_policy.h:750:8:   required from ‘std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type&&) [with _Key = char; _Pair = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Alloc = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >; _Equal = std::equal_to<char>; _H1 = std::hash<char>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = char]’
/usr/include/c++/7/bits/unordered_map.h:977:20:   required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = char; _Tp = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; _Hash = std::hash<char>; _Pred = std::equal_to<char>; _Alloc = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = char]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',31)">main.cpp:31:7</span>:   required from here
/usr/include/c++/7/bits/stl_tree.h:149:24: error: use of deleted function ‘main()::::()’
       : _M_key_compare()
                        ^
main.cpp:17:24: note: a lambda closure type has a deleted default constructor
     auto SetCompare = [](const string& a, const string& b)

GCC C++17

In file included from /usr/include/c++/6/set:60:0,
                 from main.cpp:10:
/usr/include/c++/6/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Rb_tree_impl<_Key_compare, <anonymous> >::_Rb_tree_impl() [with _Key_compare = main()::<lambda(const string&, const string&)>; bool <anonymous> = false; _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = main()::<lambda(const string&, const string&)>; _Alloc = std::allocator<std::basic_string<char> >]’:
/usr/include/c++/6/bits/stl_tree.h:821:18:   required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Rb_tree() [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = main()::<lambda(const string&, const string&)>; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/6/bits/stl_set.h:146:14:   required from ‘std::set<_Key, _Compare, _Alloc>::set() [with _Key = std::basic_string<char>; _Compare = main()::<lambda(const string&, const string&)>; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/6/tuple:1590:70:   required from ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {char&&}; long unsigned int ..._Indexes1 = {0ul}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const char; _T2 = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >]’
/usr/include/c++/6/tuple:1579:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {char&&}; _Args2 = {}; _T1 = const char; _T2 = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >]’
/usr/include/c++/6/ext/new_allocator.h:120:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _Tp = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >]’
/usr/include/c++/6/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _Tp = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >]’
/usr/include/c++/6/bits/hashtable_policy.h:1953:37:   required from ‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<char&&>, std::tuple<>}; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::__detail::_Hash_node<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >, false>]’
/usr/include/c++/6/bits/hashtable_policy.h:620:8:   required from ‘std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type&&) [with _Key = char; _Pair = std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > >; _Alloc = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >; _Equal = std::equal_to<char>; _H1 = std::hash<char>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = char]’
/usr/include/c++/6/bits/unordered_map.h:908:20:   required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = char; _Tp = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; _Hash = std::hash<char>; _Pred = std::equal_to<char>; _Alloc = std::allocator<std::pair<const char, std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> > > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::set<std::basic_string<char>, main()::<lambda(const string&, const string&)> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = char]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',31)">main.cpp:31:7</span>:   required from here
/usr/include/c++/6/bits/stl_tree.h:602:21: error: use of deleted function ‘main()::::()’
      _M_node_count(0)
                     ^
main.cpp:17:24: note: a lambda closure type has a deleted default constructor
     auto SetCompare = [](const string& a, const string& b)
                        ^
In file included from /usr/include/c++/6/set:60:0,
                 from main.cpp:10:
/usr/include/c++/6/bits/stl_tree.h:628:4: warning: ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Rb_tree_impl<_Key_compare,  >::_M_initialize() [with _Key_compare = main()::; bool  = false; _Key = std::basic_string; _Val = std::basic_string; _KeyOfValue = std::_Identity >; _Compare = main()::; _Alloc = std::allocator >]’ used but never defined
    _M_initialize()
    ^~~~~~~~~~~~~

VC C++14/17

1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\include\set(84,1): error C2280: 'main::<lambda_b1395bcc88464fd844969fa0764f137c>::<lambda_b1395bcc88464fd844969fa0764f137c>(void)': attempting to reference a deleted function
1>xx.cpp(923): message : see declaration of 'main::<lambda_b1395bcc88464fd844969fa0764f137c>::<lambda_b1395bcc88464fd844969fa0764f137c>'
1>xxx.cpp(923,20): message : 'main::<lambda_b1395bcc88464fd844969fa0764f137c>::<lambda_b1395bcc88464fd844969fa0764f137c>(void)': function was explicitly deleted
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\include\set(84): message : while compiling class template member function 'std::set<std::string,main::<lambda_b1395bcc88464fd844969fa0764f137c>,std::allocator<std::string>>::set(void)'
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\include\tuple(975): message : see reference to function template instantiation 'std::set<std::string,main::<lambda_b1395bcc88464fd844969fa0764f137c>,std::allocator<std::string>>::set(void)' being compiled
1>xxx.cpp(937): message : see reference to class template instantiation 'std::set<std::string,main::<lambda_b1395bcc88464fd844969fa0764f137c>,std::allocator<std::string>>' being compiled

Lambdas are never default constructible before C++20 (see ClosureType::ClosureType() section on cppreference ), so you must pass the SetCompare variable when constructing a MySet . Using -std=c++20 / -std=c++2a on clang or GCC should work ( demo ), as well as /std:c++latest on MSVC.

To work around this limitation in earlier C++ versions define SetCompare as a functor type:

struct SetCompare
{
    bool operator()(const string& a, const string& b)
    {
        size_t L = a.length();
        size_t R = b.length();
        if (L == R) return (a < b);
        return L < R;
    }
};

and use this type when defining MySet

using MySet = std::set<std::string, SetCompare>;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM