C++ — cast_away_const(..) revisited
In my last post I talked about writing a cast_away_const(..) function. With const_cast<..>(..) you have to specify the target type explicitly, but you can leave that out with cast_away_const(..). You can see the difference in this example.
const int c = 0; int& r1 = const_cast< int& >( c); int& r2 = cast_away_const( c);
cast_away_const(..) as it was written in the last post will not warn you if you are using it unnecessarily. (Neither will const_cast<..>(..).) Since I like to avoid casts of all types, and since I’d never cast unless I was sure I needed to, I’d like cast_away_const(..) to tell me if I’m using it frivolously.
Fortunately, this is easy to achieve. Just define non-const overloads.
# include <boost/static_assert.hpp>
template< typename T >
T&
cast_away_const( const T& a)
{
return const_cast< T& >( a);
}
template< typename T >
T&
cast_away_const( T& a)
{
// cast_away_const(..) called
// with non-const param
BOOST_STATIC_ASSERT( false);
return a;
}
template< typename T >
T*&
cast_away_const( const T*& a)
{
return const_cast< T*& >( a);
}
template< typename T >
T*&
cast_away_const( T*& a)
{
// unnecessary const cast
BOOST_STATIC_ASSERT( false);
return a;
}
template< typename T >
T* const &
cast_away_const( const T* const & a)
{
return const_cast< T* const & >( a);
}
template< typename T >
T* const &
cast_away_const( T* const & a)
{
// unnecessary const cast
BOOST_STATIC_ASSERT( false);
return a;
}
I prefer using a macro to make this more compact.
# include <boost/static_assert.hpp>
# define DEFINE_CAST_AWAY_CONST( TYPE_SUFFIX) \
\
template< typename T > \
T TYPE_SUFFIX \
cast_away_const( T TYPE_SUFFIX a) \
{ \
BOOST_STATIC_ASSERT( false); \
return a; \
} \
\
template< typename T > \
T TYPE_SUFFIX \
cast_away_const( const T TYPE_SUFFIX a) \
{ \
return const_cast< T TYPE_SUFFIX >( a); \
}
DEFINE_CAST_AWAY_CONST( & )
DEFINE_CAST_AWAY_CONST( * & )
DEFINE_CAST_AWAY_CONST( * const & )
# undef DEFINE_CAST_AWAY_CONST
And since I’m defining cast_away_const(..), I might as well define cast_away_volatile(..) and cast_away_cv(..) too (cv stands for const volatile). Although I’ve never found occasion to use volatile in my own code.
# define DEFINE_CAST_AWAY_FUNCTIONS_( \
FN_NAME, \
TYPE_PREFIX, \
TYPE_SUFFIX) \
\
template< typename T > \
T TYPE_SUFFIX \
FN_NAME( T TYPE_SUFFIX a) \
{ \
BOOST_STATIC_ASSERT( false); \
return a; \
} \
\
template< typename T > \
T TYPE_SUFFIX \
FN_NAME( TYPE_PREFIX T TYPE_SUFFIX a) \
{ \
return const_cast< T TYPE_SUFFIX >( a); \
}
# define DEFINE_CAST_AWAY_FUNCTIONS( \
FN_NAME, \
TYPE_PREFIX) \
DEFINE_CAST_AWAY_FUNCTIONS_( \
FN_NAME, TYPE_PREFIX, &) \
DEFINE_CAST_AWAY_FUNCTIONS_( \
FN_NAME, TYPE_PREFIX, * &) \
DEFINE_CAST_AWAY_FUNCTIONS_( \
FN_NAME, TYPE_PREFIX, * const &)
// Each line defines 6 overrides.
DEFINE_CAST_AWAY_FUNCTIONS( cast_away_const, const)
DEFINE_CAST_AWAY_FUNCTIONS( cast_away_volatile, volatile)
DEFINE_CAST_AWAY_FUNCTIONS( cast_away_cv, const volatile)
# undef DEFINE_CAST_AWAY_FUNCTIONS_
# undef DEFINE_CAST_AWAY_FUNCTIONS
And there you have it. Functions cast_away_const(..), cast_away_volatile(..), and cast_away_cv(..) that work for const T&, const T*&, const T* const &, volatile T&, volatile T*&, volatile T* const &, etc. And unlike const_cast<..>(..), these functions warn you if you use them unnecessarily.
Comments
Leave a Reply