c++stlconst-correctnessconst-castconst-pointer

How to find by a const pointer key in a map with non-const pointer keys


The following C++ code does not compile because it's passing a non-const pointer to a find() function which expects a const pointer.

#include <map>

std::map<int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(mykey)->second;
}

Is there a way how to make the finding work without changing the type of the map or making variable mykey non-const? After all the function find() does not modify the pointed object, it just compares the pointers.


Solution

  • I think I have found a solution, but it requires C++14 transparent comparators.

    #include <map>
    #include <iostream>
    
    struct CompareIntPtrs
    {
        using is_transparent = void; // enabling C++14 transparent comparators
    
        bool operator()(const int * l, const int * r) const
        {
            return l < r;
        }
    };
    
    std::map<int*, double, CompareIntPtrs> mymap;
    
    double myfind(const int * key)
    {
        return mymap.find(key)->second;
    }
    
    int main()
    {
        int x {6};
        mymap[&x] = 66; // inserting to the map
        const int * px = &x; // creating a "const int *" variable
    
        std::cout << myfind(px) << std::endl; // using "const int *" for finding in map with "int*" keys
        std::cout << mymap.find(px)->second << std::endl; // we could even skip using myfind()
    }
    

    An excellent article about C++14 transparent comparators can be found here. To be completely honest, by adding the comparator, the type of mymap slightly changed which I originally didn't want to, but it's the best solution I could find.

    If C++14 is not available, there are at least two evils we can choose from. The first one is to copy mymap to a new std::map<const int*, double> in myfind, which is horribly unefficient. The second one is casting away constness by using a const_cast<int*>(mykey) which should be avoided if possible.