Gileos
Gileos

Reputation: 133

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
        ^

Upvotes: 6

Views: 563

Answers (2)

Bitwize
Bitwize

Reputation: 11220

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.

Upvotes: 12

Bathsheba
Bathsheba

Reputation: 234665

You can cast away the const-ness of x with no ill-effects in this case.

Other than perhaps signalling a design flaw, the only thing you need to watch out with casting away const is that the behaviour on attempting to modify an object that was originally declared using const via the non-const pointer is undefined. That's not the case here.

Upvotes: 4

Related Questions