Search code examples
c++const-correctness

How to search for const pointer in a collection of non-const pointers?


I have a member variable std::set<T*> m_associates;, i.e., a collection of non-const raw pointers, and simply want to check for existence of another pointer. To maintain const correctness my function looks like this:

bool MyClass::is_associated(const T* x) const
{
    return (m_associates.find(x) != m_associates.end());
}

However, this does not compile, since x is passed as const T* to indicate that the value pointed to by x is not changed by the function, but m_associates contains non-const T*.

If I remove const from the x parameter, it compiles, but violates const correctness...

Adding const to m_associates, i.e., std::set<const T*> m_associates; is not an option either as I need the non-const pointers elsewhere in my class.

How do I solve this? Is this (possibly the only) point where a const_cast should be used? Or do I have to always pass all parameter T pointers as non-const?

Edit: Full error output, compiler is clang++-8, code is in C++17

error: no matching member function for call to 'find'
        return (m_associates.find(x) != m_associates.end());
                ~~~~~~~~~~~~^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:798:7: note: candidate function not viable: 1st argument ('const T *') would lose const qualifier
      find(const key_type& __x) const
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:804:2: note: candidate function template not viable: 'this' argument has type 'const std::set<T *>', but method is not marked const
        find(const _Kt& __x)
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:794:7: note: candidate function not viable: 'this' argument has type 'const std::set<T *>', but method is not marked const
      find(const key_type& __x)
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:810:2: note: candidate template ignored: substitution failure [with _Kt = const T *]: no matching member function for call to '_M_find_tr'
        find(const _Kt& __x) const
        ^

Solution

  • The reason your current code fails is that the default Compare for std::set<T> is std::less<T>; which forces both arguments to be a T for comparison -- in this case, non-const T* types. Since const T* cannot be converted to T* without casting away the constness, this is causing your compile errors.

    If you are using C++14 or above, you can redefine your std::set so that the Compare template type is a transparent comparator (one that deduces the underlying types for comparison), for example std::set<T*, std::less<>>. This will enable the overload of std::set::find that deduces the type and forwards the argument to the comparator, which will enable the above code to work.