member_object_pointer_traits
Yesterday I wrote about const_cast<T>(..) and how to define it in C++. But I did not make it work with data-member pointers because the Boost Type Traits library does not supply traits for data member objects. Here I’ll show you how to write type-traits and supporting template functions for data members. We’ll define the following templates:
- member_object_pointer_traits<T>
- add_member_object_pointer_const<T>
- remove_member_object_pointer_const<T>
- add_member_object_pointer_volatile<T>
- remove_member_object_pointer_volatile<T>
- add_member_object_pointer_cv<T>
- remove_member_object_pointer_cv<T>
We’ll start with the headers.
# include <boost/type_traits.hpp> using boost::is_same; using boost::add_const; using boost::add_volatile; using boost::add_cv; using boost::remove_const; using boost::remove_volatile; using boost::remove_cv; using boost::remove_pointer; # include <boost/mpl/assert.hpp> // BOOST_MPL_ASSERT(..) // BOOST_MPL_ASSERT_NOT(..)
Boost (1_36) already provides these template functions that deal with members.
- is_member_pointer<T>
- is_member_function_pointer<T>
- is_member_object_pointer<T>
Using a similar naming convention we’ll define member_object_pointer_traits<T>. Something like this will probably be part of Boost soon, along with member_function_pointer_traits<T>.
// Declare member_object_pointer_traits but do not
// define a body. The struct will only ever be
// instantiated through specialization.
template< typename DATA_MEMBER_PTR >
struct member_object_pointer_traits;
// Specialized member_object_pointer_traits that
// only matches member-object pointers.
template< typename T, typename C >
struct member_object_pointer_traits< T (C::*) >
{
typedef C class_type;
typedef T data_type;
};
We’d also like to be able to manipulate member-object pointers using functions like these:
- add_const<T>
- remove_const<T>
- add_volatile<T>
- remove_volatile<T>
- add_cv<T>
- remove_cv<T>
- add_pointer<T>
- remove_pointer<T>
But remove_pointer<T> cannot remove the pointer from member-object pointer types because the result is not a valid type. Also, add_const<T> and remove_const<T> cannot add/remove const that is buried in the member-object pointer.
// 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 */
// Confirm that regular type-traits functions
// do not work with member-object pointer types.
// remove_pointer<T> does nothing
BOOST_MPL_ASSERT( (is_same<
remove_pointer<
ptr_non_c_member_obj_type
>::type,
ptr_non_c_member_obj_type
>));
// remove_const<T> does nothing
BOOST_MPL_ASSERT( (is_same<
remove_const<
ptr_const_member_obj_type
>::type,
ptr_const_member_obj_type
>));
// add_const<T> adds const outside the
// type and does not affect the inner const.
BOOST_MPL_ASSERT( (is_same<
add_const<
ptr_non_c_member_obj_type
>::type,
const
ptr_non_c_member_obj_type
>));
We can define special add/remove functions that work just with member-object pointer types using member_object_pointer_traits<T> which we defined above.
# define DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( PRE, POST ) \
template< typename T > \
struct PRE ## _member_object_pointer_ ## POST \
{ \
typedef member_object_pointer_traits< T > \
traits_type; \
\
typedef typename traits_type::class_type \
class_type; \
\
typedef typename traits_type::data_type \
data_type; \
\
typedef typename PRE ## _ ## POST< data_type >::type \
adjusted_data_type; \
\
/* Construct a member-object-pointer type */ \
/* around the adjusted inner type. */ \
typedef adjusted_data_type (class_type::* \
type); \
}
// remove_member_object_pointer_const<T>
// remove_member_object_pointer_volatile<T>
// remove_member_object_pointer_cv<T>
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( remove, const );
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( remove, volatile);
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( remove, cv );
// add_member_object_pointer_const<T>
// add_member_object_pointer_volatile<T>
// add_member_object_pointer_cv<T>
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( add, const );
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( add, volatile);
DEFINE_MEMBER_OBJECT_POINTER_FUNCTION( add, cv );
# undef DEFINE_MEMBER_OBJECT_POINTER_FUNCTION
// Test some of the above template functions:
BOOST_MPL_ASSERT( (is_same<
remove_member_object_pointer_const<
ptr_const_member_obj_type
>::type,
ptr_non_c_member_obj_type
>));
BOOST_MPL_ASSERT( (is_same<
add_member_object_pointer_const<
ptr_non_c_member_obj_type
>::type,
ptr_const_member_obj_type
>));
And that’s how we can define template functions for working with member-object pointers in the Boost style. The traits for member-function pointers will resemble the function-traits class and will be more complicated.
We’ll use the templates we’ve defined here in the next post, when we extend our version of const_cast<T>(..) to work with member-object-pointers.
Comments
One Response to “member_object_pointer_traits”
Leave a Reply
Many thanks, just what I was looking for. Unfortunately boost::type_traits 1.43 still seems to be missing member_object_pointer_traits.
Your blog helped me a lot.