c++stlmultimapstd-pair

Finding a key-value-pair within a std::multimap with key of type int


I have a std::multimap<int, X*> where X is a user-defined type. I want to find a specific key-value-pair within this multimap (i.e. an iterator pointing to this pair).

(A) Complete Example:

#include <map>
#include <algorithm>

class X {};

int main()
{
    X myX;
    std::multimap<int, X*> myMap;
    auto it = std::find(myMap.begin(), myMap.end(), std::make_pair(5, &myX));
    
    return 0;
}

However, this does not compile (gcc 12.2.1 with -std=gnu++2a):

no match for ‘operator==’ (operand types are ‘std::pair<const int, X*>’ and ‘const std::pair<int, X*>’)

So it seems to me somehow int gets converted to const int.

(B) Using std::find_if with a lamdba function with const int, the code compiles:

auto it = std::find_if(myMap.begin(), myMap.end(), [myX](std::pair<const int, X*>& node){ return 5 == node.first && (&myX) == node.second; } );

Questions:

  1. Why is the type of the keys in the multimap const int and not int?
  2. How to fix it in a more natural way than using a (complex) lambda function like in (B) or by first looking up by key and then searching within its values (as described by Igor Tandetnik in the comments)?

Solution

  • Why is the type of the keys in the multimap const int and not int?

    Because the Key in all standard maps is immutable.

    How to fix it in a more natural way than using a (complex) lambda function like in (B) or by first looking up by key and then searching within its values?

    Here's a simplified example that doesn't use X* but X in the map:

    #include <algorithm>
    #include <iostream>
    #include <map>
    
    struct X {
        bool operator==(const X& rhs) const { return m_value == rhs.m_value; }
    
        int m_value;
    };
    
    int main() {
        std::multimap<int, X> myMap{
            {4, {1}}, {5, {2}}, {6, {3}}, {4, {4}}, {5, {5}}, {6, {6}}
        };
    
        // get the range of _Key_s equal to 5
        auto [first, last] = myMap.equal_range(5);
    
        // the lambda - here used to find the first entry with the _Value_ `X{2}`    
        auto cond = [](auto&& pair) { return pair.second == X{2}; };
    
        if (auto it = std::find_if(first, last, cond); it != last)
        {
            auto& [k, v] = *it;
    
            std::cout << k << ' ' << v.m_value << '\n';
        }
    }
    

    Demo


    If many Values may be found, just put the find_if in a loop:

        for(;(first = std::find_if(first, last, cond)) != last; ++first) {
            auto& [k, v] = *first;
    
            std::cout << k << ' ' << v.m_value << '\n';
        }
    

    Demo