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:

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.

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:

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”

  1. Hajo Kirchhoff on July 14th, 2010 2:50 am

    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.

Leave a Reply