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