[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

meta reflection in c++

john

12/5/2008 9:41:00 PM


http://groups.google.com/group/comp.lang.c++/browse_thread/thread/5e6bf45e1bf2a8a0?hl=en&ie=UTF-8&q=noah+roberts...

Looking in google groups I saw this and decided to post a different kind
of implementation.

This also explains some of my more recent conversations about member
variable pointers. Ideas and critique for improvement would be cool if
you want...but it's really just to show off (though it does have
practical purposes and I'm using it). Feel free to ask questions also.

Warning: Some of you anti-template types will more than likely see this
as an abuse of the language. Don't look if you think it's going to give
you a coronary.

STATIC REFLECTION IN C++
==================================================

#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/for_each.hpp>

//#define MSVC // uncomment if you have visual studio. Also fine in g++

#define DECLARE_FIELD(NAME,TYPE) struct NAME { typedef TYPE type; static char const* name() { return #NAME ; } }


template < typename CONT, typename FIELD, typename TYPE, TYPE CONT::*addr >
struct record_field_desc
{
typedef CONT member_of;
typedef FIELD field;
typedef TYPE type;

static TYPE get(CONT const& cont) { return cont.*addr; }
static void set(CONT & cont, TYPE const& value) { cont.*addr = value; }
};

template < typename REC >
struct meta
{
typedef typename REC::meta type;
};
#ifndef MSVC

#define BEGIN_META(CONT) struct meta { typedef boost::mpl::vector<CONT

#define ADD_FIELD(CONT, FIELD, ADDR) , record_field_desc<CONT, FIELD, FIELD::type, ADDR>

#define END_META() > fields; typedef boost::mpl::next<boost::mpl::begin<fields>::type>::type begin; typedef boost::mpl::end<fields>::type end; };

#else
// In MSVC the meta structure must be declared outside of the class
since the address of member variables
// can't be taken in class declaration scope with that compiler.
#define BEGIN_META(CONT) struct CONT_meta { typedef boost::mpl::vector<CONT

#define ADD_FIELD(CONT, FIELD, ADDR) , record_field_desc<CONT, FIELD, FIELD::type, ADDR>

#define END_META(CONT) > fields; typedef boost::mpl::next< boost::mpl::begin<fields>::type >::type begin; typedef boost::mpl::end<fields>::type end; }; template <> struct meta<CONT> { typedef CONT_meta type; };

#endif

DECLARE_FIELD(test1, int);
DECLARE_FIELD(test2, double);
DECLARE_FIELD(test3, long);

struct test_record
{
int x;
double y;

#ifndef MSVC
BEGIN_META(test_record)
ADD_FIELD(test_record, test1, &test_record::x)
ADD_FIELD(test_record, test2, &test_record::y)
//ADD_FIELD(test_record, test3, &test_record::y) // uncomment to
see error
END_META()
#endif
};

#ifdef MSVC
BEGIN_META(test_record)
ADD_FIELD(test_record, test1, &test_record::x)
ADD_FIELD(test_record, test2, &test_record::y)
END_META(test_record)
#endif



// UTILITY STUFF
template < typename T >
struct type_desc
{
static char const* desc() { return typeid(T).name(); }
};
template <>
struct type_desc<int> { static char const* desc() { return "integer"; } };
template <>
struct type_desc<double> { static char const* desc() { return "real
number"; } };

template < typename REC >
struct record_reader
{
struct field_reader
{
REC & rec;
field_reader(REC & r) : rec(r) {}

template < typename FIELD_DESC >
void operator() (FIELD_DESC const&) const
{
typedef typename FIELD_DESC::type type;
std::cout << "Enter a " << type_desc<type>::desc() << " for " <<
FIELD_DESC::field::name() << ": ";

type t;
std::cin >> t;

FIELD_DESC::set(rec, t);
}
};

static REC read_record()
{
REC rec;
boost::mpl::for_each< typename meta<REC>::type >(field_reader(rec));
return rec;
}
};

template < typename REC >
struct record_writer
{
struct field_writer
{
REC const& rec;
field_writer(REC const& r) : rec(r) {}

template < typename FIELD_DESC >
void operator() (FIELD_DESC const&) const
{
std::cout << "Value for "
<< FIELD_DESC::field::name()
<< " is: " << FIELD_DESC::get(rec) << std::endl;
}
};

static void write_record(REC const& r)
{
boost::mpl::for_each< typename meta<REC>::type >(field_writer(r));
}
};

int main()
{
test_record rec = {};
record_writer<test_record>::write_record(rec);

rec = record_reader<test_record>::read_record();

record_writer<test_record>::write_record(rec);
}

======================================

With a series of other helper metafunctions you can develop functions
that toss compile time asserts if a field is not contained in a record,
or even do conditional selection of template specializations based on such.

Purpose was to develop a way of working with a library of objects
containing different sets of data to which objects can be added to all
the time. Didn't want to have to go deriving all the GUI stuff and such
for every single one....and wanted to keep type safety.

In the real implementation (that's just a skeleton/poc above) there's a
dynamic reflection parallel. It's built by the static reflection API.

The real implementation also has a function counterpoint to the field
descriptor so that function calls can be "fields".