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
^
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.