Home > Enterprise >  Keying an (unordered_)map using a multimap iterator
Keying an (unordered_)map using a multimap iterator

Time:10-17

I'm building a software where one class is responsible to log info sources and commands (both are grouped as requests), where all requests are inserted inside a multimap, wherein the multimap is keyed by the request name, and each element points to request structure that holds management information and callback function pointer, insighted from this software.

The callbacks are executed to issue a command, or to get an info, and everything is ok until here.

To enable subscription-based information delivery, I've introduced a new map keyed by the request iterator, so where calling subscribe("infoID") the software looks for the exact match request and return its iterator.

Because these iterators are unique per request, I've found it useful to key the subscriptions map using it. Where the key points to info subscriber's callback-functions.

The error is:

error: no match for 'operator<' (operand types are 'const std::__detail::_Node_iterator<std::pair<const std::__cxx11::basic_string, request>, false, true>' and 'const std::__detail::_Node_iterator<std::pair<const std::__cxx11::basic_string, request>, false, true>') { return __x < __y; }

Followed by 15 compiling notes 'template argument deduction/substitution failed':

'const std::__detail::_Node_iterator<std::pair<const std::__cxx11::basic_string, request>, false, true>' is not derived from 'const std::pair<_T1, _T2>' { return __x < __y; } each one with a unique source: const std::pair<_T1, _T2>, const std::reverse_iterator<_Iterator> (stl_function.h), const std::reverse_iterator<_Iterator> (stl_iterator.h), ... etc.

Full error here.

Code:

#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <functional>
#include <map>

using namespace std;

struct request
{
    string f1;
};

using   SYS_REQMAP          =unordered_multimap<string, request, hash<string>>;
using   SYS_REQMAP_I        =SYS_REQMAP::iterator;

using SYS_INFOSUB_CBF   = function<void(string, string)>;
using SYS_INFOSUB_CBFS  = vector<SYS_INFOSUB_CBF>;

using SYS_REQINF_SUBS   = map<SYS_REQMAP_I, SYS_INFOSUB_CBFS>;

void cbf(const string& a, const string& b){}
int main()
{
    SYS_REQINF_SUBS infoSubr;
    SYS_REQMAP vm{{"cmd1", {"foo"}},
                {"cmd2", {"bar"}}};

    for (SYS_REQMAP_I it = vm.begin(); it != vm.end(); it  )
    {
        infoSubr[it].push_back(cbf);    // Compile error
    }
}

void compilesOK()
{
    using SYS_REQINF_SUBS_1 = std::map<int, SYS_INFOSUB_CBFS>;
    SYS_REQINF_SUBS_1 subs1;
    subs1[1].push_back(cbf);    // Compiles OK
}

And here's OnlineGDB link to compile and observe output.

CodePudding user response:

The key part of the error is:

stl_map.h:481:32:   required from 'std::map<_Key, _Tp, _Compare, ....>
[with _Key = std::__detail::_Node_iterator ....
...
stl_function.h:386:20: error: no match for 'operator<'

std::map (aka ordered map) keys are required to be comparable (operator<), but map iterators are not comparable, and thus cannot be used in an ordered map.

The simpliest solutions is to use some other type.

Other solutions are to provide the map with a comparitor (_Compare), to tell it how to compare iterators, or switch to a unordered_map and provide a hasher to tell it how to hash iterators.

CodePudding user response:

The iterator requires a custom comparison function _Compare:

struct Compare_REQMAP_I
{
    bool operator()(const SYS_REQMAP_I& lhs, const SYS_REQMAP_I& rhs) const {
        return &lhs < &rhs;
    }
};

using SYS_REQINF_SUBS   = std::map<SYS_REQMAP_I, SYS_INFOSUB_CBFS, Compare_REQMAP_I>;
  • Related