Experimental code for simulating Reflection in C++

Motivation for looking at Reflection in C++

At work, we have two frameworks for developing new components – one in C++ and the other in F#. The F# framework is newer and benefits from the insight of previous years working with the C++ framework. In particular, the new F# framework only requires developers to implement a reduced, strongly typed interface in F# by defining a few types (e.g. records) and associated functions between them. This reduced interface is inflated into a full model by the framework, making heavy use of .NET Reflection.

The F# framework has delivered productivity improvements (development time down to a third compared to the previous C++ framework). But the philosophical question remains – how much of that is due to the new architecture developed with the benefit of hindsight? And could we replicate that architecture in C++? The main functionality gap comes down to this: in F# you can use .NET Reflection to discover the names and types of fields in F# types such as unions, records and options, but in C++ you can’t.

Requirements

A full implementation of Reflection for C++ would include ability to discover type information, field names, properties and methods, as well as being able to create instances of types and invoke methods.  I’m interested in a small subset of that scope – the ability to discover the names and values of fields in a C++ struct.

Solution

#include "stdafx.h"

#include <iostream>
#include <string>

#include <boost\preprocessor.hpp>
#include <boost\preprocessor\variadic\size.hpp>
#include <boost\type_traits.hpp>

#include <boost\mpl\range_c.hpp>
#include <boost\mpl\for_each.hpp>

#define REMOVE_BRACKETS(...) __VA_ARGS__
#define REMOVE_NEXT(x)
#define STRIP_TYPE(x) REMOVE_NEXT x
#define DECLARE_DATA_MEMBER(x) REMOVE_BRACKETS x
#define TYPE_ONLY(x) x REMOVE_NEXT(

#define REFLECTABLE(...) \
  static const int number_of_fields = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); \
  friend struct Reflector; \
  \
  template<int N, class Parent = void> \
  struct FieldData {}; \
  \
  BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

#define REFLECT_EACH(r, data, i, x) \
  DECLARE_DATA_MEMBER(x); \
  template<class Parent> \
  struct FieldData<i, Parent> \
  { \
    Parent & parent; \
    FieldData(Parent& p) : parent(p) {} \
    \
    TYPE_ONLY x ) & get() const \
    { \
      return parent.STRIP_TYPE(x); \
    }\
    const char * name() const \
    {\
      return BOOST_PP_STRINGIZE(STRIP_TYPE(x)); \
    } \
  }; \

struct Reflector
{
  // Get a FieldData instance for the N'th field in type T
  template<int N, class T>
  static typename T::template FieldData<N, T> getFieldData(T& x)
  {
    return typename T::template FieldData<N, T>(x);
  }

  // Reflector is a friend of T, so has access to the private member T::number_of_fields
  template<class T>
  struct FieldCounter
  {
    static const int count = T::number_of_fields;
  };
};

// FieldDispatcher - calls Visitor::visit for each field in T
template<class T, class Visitor>
struct FieldDispatcher
{
  FieldDispatcher( T& t, Visitor visitor ) :
  t(t),
  visitor(visitor)
  {
  }

  template<class FieldIterator>
  void operator()(FieldIterator)
  {
    auto field = Reflector::getFieldData<FieldIterator::value>(t);
    visitor.visit( field );
  }

  T& t;
  Visitor visitor;
};

template<class T, class Visitor>
void for_each_field(T& t, Visitor visitor)
{
  typedef boost::mpl::range_c<int, 0, Reflector::FieldCounter<T>::count> FieldList;
  FieldDispatcher<T, Visitor> field_dispatcher( t, visitor );

  // For each field in T, dispatch the visitor to that field
  boost::mpl::for_each<FieldList>( field_dispatcher );
}

struct PrintNameValueVisitor
{
  template<class FieldData>
  void visit( FieldData field )
  {
    std::cout << field.name() << "=" << field.get() << std::endl;
  }
};

struct Person
{
  Person(const char *first_name, int age, const char* street, const char* town) :
    first_name(first_name),
    age(age),
    street_name(street),
    town(town)
    {
    }

  REFLECTABLE
  (
    (const char *) first_name,
    (int) age,
    (std::string) street_name,
    (std::string) town
  )
};

int _tmain(int argc, _TCHAR* argv[])
{
  Person p("John", 31, "Electric Avenue", "Harrogate" );
  for_each_field(p, PrintNameValueVisitor());

  return 0;
}

Output

Output

Conclusions

The code above ‘works’ – it satisfies the requirements by providing a way to decorate a struct with metadata that can be used to return the names and values of each field. However, in Visual Studio 2010 and 2012, it produces compiler warnings (due to the macro hackery in TYPE_ONLY) and confuses intellisense (which doesn’t cope with the REFLECTABLE macro). In practical terms, that makes it unsuitable, because the productivity benefits are lost when intellisense and auto-complete stop working.

2 Comments

Filed under C++ Code

2 responses to “Experimental code for simulating Reflection in C++

  1. Paul

    You should be able to make it work in visual studio if you define your `TYPE_ONLY` macro like this:

    #define REM(…) __VA_ARGS__
    #define TYPE_ONLY(x) DETAIL_TYPE_ONLY(DETAIL_TYPE_ONLY_PROBE x,)
    #define DETAIL_TYPE_ONLY_INVOKE(m, args) m args
    #define DETAIL_TYPE_ONLY(…) DETAIL_TYPE_ONLY_INVOKE(DETAIL_TYPE_ONLY_HEAD, (__VA_ARGS__))
    #define DETAIL_TYPE_ONLY_HEAD(x, …) REM x
    #define DETAIL_TYPE_ONLY_PROBE(…) (__VA_ARGS__),

    • Thanks Paul – I agree that’s an improvement over the TYPE_ONLY macro in the posted code. Unfortunately, it still doesn’t play nicely with intellisense in Visual Studio though. I’m not giving up yet though!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.