Improved const_cast<T>(..) definition in C++
A few days ago I talked about how to define const_cast<T>(..) as a templated function. My solution could not cast the const out of a data-member pointer however, because I did not have the type traits functions needed for the job.
But yesterday I posted code to supply type-traits style functions to manipulate data-member pointers which I can use to improve my implementation of const_cast<T>. This post is a listing of that improved implementation, which is called const_cast_x<T>.
I start with the type-traits template functions.
# include <boost/type_traits.hpp> using boost::is_same; using boost::is_pointer; using boost::is_reference; using boost::is_member_object_pointer; using boost::add_const; using boost::add_volatile; using boost::add_cv; using boost::add_pointer; using boost::add_reference; using boost::remove_const; using boost::remove_volatile; using boost::remove_cv; using boost::remove_pointer; using boost::remove_reference; using boost::mpl::identity; using boost::mpl::if_;
I also need the following template functions from my previous post.
- member_object_pointer_traits<T>
- add_member_object_pointer_cv<T>
- remove_member_object_pointer_cv<T>
The improved const_cast_x<T> follows. Most of it is just copied from my earlier post. I have identified the changed parts in code comments, and I have taken out all the BOOST_MPL_ASSERT(..) and other explanatory and testing code in order to keep it brief. There are only two new template functions and two functions that have changed from the earlier version.
// ================================================
// strip_out_cv<T>
// strip_out_member_obj_ptr_cv<T>
// new, not in earlier code listing
template< typename T >
struct strip_out_member_obj_ptr_cv
: if_<
is_member_object_pointer< T >,
remove_member_object_pointer_cv< T >,
identity< T >
>::type
{ };
// strip_out_cv_no_ref<T>
// no change from earlier code listing
template< typename T, bool IS_PTR = is_pointer< T >::value >
struct strip_out_cv_no_ref
: add_pointer<
typename strip_out_cv_no_ref<
// remove_pointer<T> will remove top-level
// const and volatile if they are present.
typename remove_pointer<
T
>::type
>::type
>
{ };
// strip_out_cv_no_ref<T> specialization
// changed from earlier code listing
template< typename T >
struct strip_out_cv_no_ref< T, false >
: strip_out_member_obj_ptr_cv<
typename remove_cv< T >::type
>
{ };
// strip_out_cv_maybe_ref<T>
// no change from earlier code listing
template< typename T, bool IS_REF = is_reference< T >::value >
struct strip_out_cv_maybe_ref
: add_reference<
typename strip_out_cv_no_ref<
typename remove_reference<
T
>::type
>::type
>
{ };
// strip_out_cv_maybe_ref<T> specialization
// no change from earlier code listing
template< typename T >
struct strip_out_cv_maybe_ref< T, false >
: strip_out_cv_no_ref< T >
{ };
// strip_out_cv<T>
// no change from earlier code listing
template< typename T >
struct strip_out_cv
: strip_out_cv_maybe_ref< T >
{ };
// ================================================
// load_with_cv<T>
// load_with_member_obj_ptr_cv<T>
// new, not in earlier code listing
template< typename T >
struct load_with_member_obj_ptr_cv
: if_<
is_member_object_pointer< T >,
add_member_object_pointer_cv< T >,
identity< T >
>::type
{ };
// load_with_cv_no_ref<T>
// no change from earlier code listing
template< typename T, bool IS_PTR = is_pointer< T >::value >
struct load_with_cv_no_ref
: add_cv<
typename add_pointer<
typename load_with_cv_no_ref<
typename remove_pointer<
T
>::type
>::type
>::type
>
{ };
// load_with_cv_no_ref<T> specialization
// changed from earlier code listing
template< typename T >
struct load_with_cv_no_ref< T, false >
: add_cv<
typename load_with_member_obj_ptr_cv< T >::type
>
{ };
// load_with_cv_maybe_ref<T>
// no change from earlier code listing
template< typename T, bool IS_REF = is_reference< T >::value >
struct load_with_cv_maybe_ref
: add_reference<
typename load_with_cv_no_ref<
typename remove_reference<
T
>::type
>::type
>
{ };
// load_with_cv_maybe_ref<T> specialization
// no change from earlier code listing
template< typename T >
struct load_with_cv_maybe_ref< T, false >
: load_with_cv_no_ref< T >
{ };
// load_with_cv<T>
// no change from earlier code listing
template< typename T >
struct load_with_cv
: load_with_cv_maybe_ref< T >
{ };
// ================================================
// const_cast_x<T>
// const_cast_x<T>
// no change from earlier code listing
template< typename TRG >
inline
TRG
const_cast_x( typename load_with_cv< TRG >::type a)
{
return (typename strip_out_cv< TRG >::type) a;
}
Finally, here is some code that confirms that this improved const_cast_x<T> now works like const_cast<T> when casting data-member pointers.
// Define type a_class.
class a_class { public: int a_data_member; };
// Define non-const data-member pointer type.
typedef
int a_class::*
ptr_non_c_member_obj_type; /* new type name */
// Define const data-member pointer type.
typedef
const int a_class::*
ptr_const_member_obj_type; /* new type name */
// Get a pointer to a non-const member object.
ptr_non_c_member_obj_type
p_non_c_memb =
& a_class::a_data_member;
// You can assign a pointer to a non-const
// to a pointer to a const member object
// without casting.
ptr_const_member_obj_type
p_const_memb =
p_non_c_memb;
// You have to cast to assign a const
// to a non-const member-object pointer.
ptr_non_c_member_obj_type
p_non_c_memb2 =
const_cast<
ptr_non_c_member_obj_type
>( p_const_memb);
// const_cast_x<T> can also perform
// this cast with the modifications
// described above.
ptr_non_c_member_obj_type
p_non_c_memb3 =
const_cast_x<
ptr_non_c_member_obj_type
>( p_const_memb);
In closing, let me reiterate that it should be a goal to define const_cast<T> and the other primitive casting functions in C++. If the casts cannot be expressed as functions then we have found an expressive weakness in C++. And the functional definitions will give us an exact definition for these casts based on the C-style cast.
Comments
Leave a Reply