equal_range and 2 overloads have no legal conversion for 'this' pointer

732 views Asked by At

Here is this simple code

#include <map>

class MyMap : public std::multimap<int*, int*>
{
    public:
    void foo(const int* bar) const
    {
        equal_range(bar);
    }
};


int main()
{
    MyMap myMap;

    int number;
    myMap.foo(&number);

    return 0;
}

It doesn't compile, and give the following error

error C2663: 'std::_Tree<_Traits>::equal_range' : 2 overloads have no legal conversion for 'this' pointer

I have seen many topic about this error, and it seems that it is a const issue. It compiles fine if I turn foo(const int* bar) into foo(int* bar).

Problem is, I don't see how foo content is supposed to change anything to my MyMap object. std::multimap proposes a const version of equal_range:

http://www.cplusplus.com/reference/map/multimap/equal_range/

What is my problem?

Thank you

3

There are 3 answers

0
Than21 On

I believe that the problem has to do with the mismatch on the key_type. On one hand you have a multimap where key_type=int* while on the other hand you are passing a key_type=const int* thus attempting to drop the const qualifier on the key_type. I was confused by this too because I was expanding the key_type in my mind to get const int*& which should be compatible. However, the mismatch happens earlier on the key_type itself. At least that's the only logical explanation I could think of.

My suggestion would be to make the key_type const int* and keep your function parameter as is. After all, why would you need a pointer to a mutable value as a key to a map ?

1
Tim Meyer On

Check the definition of equal_range:

pair<const_iterator,const_iterator> equal_range (const key_type& k) const;

It expects a constant reference to key_type: const key_type& k.

What you were trying to supply was a pointer to a constant integer: const int* bar

Why doesn't this work even though both values are const?

  • A constant reference to an integer const int& foo means that you cannot let foo refer to another integer, but it is allowed to change the value of the referenced integer.
  • A pointer to a constant integer const int* foo means that you can let foo point to another integer, but you cannot change the value of the integer it points to.

What the map actually expects is a const int*& k, but the map will automatically convert this if you supply a int* only (without the const).

[Edit]

Also note that a MyMap object still cannot be changed by your foo function even if you change const int* to int* as there still is another const at the end of your foo function. This const at the very end declares the function as constant meaning that it cannot modify the current object in which it is executed. If it was trying to modify it or call anything that could potentially modify it, you would get a compiler error. (Disclaimer: There are ways to modify a class from within a const function anyway but that's another topic.)

0
iavr On

If fact the right compiler message can give you the answer. For one of the two overloads (the const one):

/usr/local/include/c++/v1/map:1836:41: note: candidate function not viable: 1st argument ('const int *')
      would lose const qualifier

const int* is a pointer to a const int. The method expects a const key_type&, i.e. const int*& argument, that is a const reference to a (non-const) int*.

When confused, prefer to write const int* as int const*, which is the same thing. Then you'll see the difference to const int*& more clearly.

For your code to work, use int* instead of const int*.