Reputation: 133
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
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
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