I'm providing a const and non-const variation of a member function where I reuse the const version to implement the non-const version as described in this answer per Scott Meyers books.
The const version takes an argument of type:
const std::function< void (const Foo &) > &
vs the non-const takes an argument of type:
const std::function< void ( Foo &) > &
In the implementation, I have to use reinterpret_cast
because const_cast
is not working.
E.g.,:
const std::function< void (Foo &) > & Processor;
reinterpret_cast< const std::function< void (const Foo &) > & >( Processor );
vs
const std::function< void (Foo &) > & Processor;
const_cast< const std::function< void (const Foo &) > & >( Processor );
Wouldn't this be in the spirit of what const_cast
is meant for? Is this just an oversight in the language definition to perhaps be fixed in C++2x or would const_cast
never be in the spirit of things here?
Here is more complete code:
void Collection::ProcessCollection(const std::function< void (const Foo &) > & Processor) const
{
for( int idx = -1 ; ++idx < m_LocalLimit ; )
{
if ( m_Data[ idx ] )
{
Processor( m_Data[idx] );
}
}
const int overflowSize = OverflowSize();
for( int idx = -1 ; ++idx < overflowSize ; )
{
Processor( (*m_Overflow)[ idx ] );
}
}
void Collection::ProcessCollection(const std::function< void (Foo &) > & Processor)
{
const Collection * constThis = const_cast< const Collection * >( this );
const std::function< void (const Foo &) > & constProcessor
= reinterpret_cast< const std::function< void (const Foo &) > & >( Processor );
constThis->ProcessCollection( constProcessor );
}
Generally speaking, it's not safe to use const_cast
to cast away const
ness that appears in template arguments. For example, consider this (admittedly, somewhat contrived) code:
template <typename T> struct Wrapper {
int x;
};
template <> struct Wrapper<char *> {
double y;
};
Here, a pointer to a Wrapper<const char *>
points to a very different object than a Wrapper<char *>
, so doing a const_cast
to turn a Wrapper<const char *> *
into a Wrapper<char *> *
would result in a pointer to a struct
containing an int
now pointing at a struct
containing a double
, breaking some language rule whose name eludes me at the moment. :-)
Since in general it's not safe to const_cast
this way, the language spec doesn't allow for const_cast
to be used like this, which is why in your case, even though the operation makes intuitive sense, the language disallows your code with const_cast
.
I am fairly certain that using a reinterpret_cast
here leads to undefined behavior, since the language considers std::function<T1>
and std::function<T2>
to be different, incompatible types when T1
and T2
aren't the same. It may happen to work on your system by pure coincidence, but I don't believe you can safely assume this will work.