This version of the reflection library supports reflecting member variables and base classes.
These entities get reflected through the use of macros. A reflected class has members to allow generative algorithms
to access the reflected entities.
Defining reflected entities in a class must be preceded by
BEGIN_REFLECTION(YourClass) or BEGIN_REFLECTION_NO_CTOR(YourClass) and
followed by END_REFLECTION after the last reflected
entity (base class or member variable) is mentioned.
BEGIN_REFLECTION_NO_CTOR(YourClass) defines all the scaffolding I did need to get
reflection running.
Apart from that it defines two inline functions:
static const std::string& getClassName(); void initReflectedMembers();
BEGIN_REFLECTION(YourClass) calls BEGIN_REFLECTION_NO_CTOR(YourClass) and defines a default constructor for YourClass that default initializes all reflected pod members of that class in its body.
Among other things END_REFLECTION lets the compiler calculate the number of reflected membervariables and the number of reflected direct base classes.
Member variables can be reflected with the following macros:
Base classes can be reflected with the following macros:
All these Macros must be placed in the same scope that the corresponding entities belong to.
Example:
class RefMember { public: BEGIN_REFLECTION_NO_CTOR(RefMember) protected: DEF_REFLECTED_ATTRIBUTE_NO_SETTER(const unsigned int&, RefMemberI) END_REFLECTION public: RefMember(unsigned int& i):RefMemberI_(i) { } private: struct Nest { BEGIN_REFLECTION(Nest) DEF_REFLECTED_ATTRIBUTE(std::vector<int>, Eggs) END_REFLECTION }; };
You may leave empty lines between the macros but you may not have more than one attribute or baseclass definition on each line. (actually you can have one attribute definition and one baseclass definition on the same line but not several attribute definitions or several baseclass definitions on the same line).
I'll explain what these macros do by showing what the preprocessor does. (The Visual C++ 6.0 version is not shown).
If you only want to preprocess reflected classes it might help to uncomment the line: //#define FORMAT_PREPROCESSED_OUTPUT in definereflection.h - then you can find and replace the token ctrl_h_linefeed with appropriate linefeeds)
The previous Example (
class Example:public virtual ExampleBase { BEGIN_REFLECTION(Example) DEF_REFLECTED_VIRTUAL_BASECLASS(ExampleBase) DEF_REFLECTED_ATTRIBUTE(std::string,InstanceMember) DEF_REFLECTED_STATIC_ATTRIBUTE(std::string, ClassMember) END_REFLECTION };
) expands as follows(some implementation details omitted).
class Example : public virtual ExampleBase { public: static const std::string& getClassName() { static const std::string className("Example"); return className; } void initReflectedMembers() { refl::initReflectedMembers(*this); } struct ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END; struct ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END; struct ERROR_ERROR_ERROR_not_a_valid_baseclass_num_ERROR_END; template<int No, int Dummy = 0> struct GetNameTag { typedef ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END type; }; template<int No, int Dummy = 0> struct GetValueType { typedef ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END type; typedef ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END ref_type; typedef ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END const_ref_type; }; template<class Tag, int Dummy = 0> struct GetValueTypeByTag { typedef ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END type; typedef ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END ref_type; typedef ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END const_ref_type; }; template<int No, int Dummy = 0> struct GetMemberKind { typedef ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END type; }; template<class Tag, int Dummy = 0> struct GetMemberKindByTag { typedef ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END type; }; template<int No, int Dummy = 0> struct GetBaseClass { typedef ERROR_ERROR_ERROR_not_a_valid_baseclass_num_ERROR_END type; enum {isVirtual = false}; }; typedef Example ThisClass; Example::Example() { initReflectedMembers(); }
Each reflected class has compiletime functions to access the reflected types. The default implementation of these functions is choosen to trigger a compiler error if used erroneously. The additional dummy parameter is needed because ANSI C++ does not allow full specialization of a template class at class scope.
template<int Dummy> struct GetBaseClass<ExampleBaseNum, Dummy> { typedef ExampleBase type; enum { isVirtual = true}; };
struct InstanceMember{}; template<int Dummy> struct GetNameTag<InstanceMemberNum, Dummy> { typedef InstanceMember type; }; template<int Dummy> struct GetValueType<InstanceMemberNum, Dummy> { typedef std::string type; typedef ::boost::add_reference<std::string >::type ref_type; typedef ::boost::add_const<type>::type const_type; typedef ::boost::add_reference<const_type>::type const_ref_type; }; template<int Dummy> struct GetValueTypeByTag<InstanceMember, Dummy> { typedef std::string type; typedef ::boost::add_reference<std::string >::type ref_type; typedef ::boost::add_const<type>::type const_type; typedef ::boost::add_reference<const_type>::type const_ref_type; }; template<int Dummy> struct AttributePos<InstanceMember, Dummy> { enum {value = InstanceMemberNum}; };
static const std::string& getAttributeName(InstanceMember) { static const std::string attName("InstanceMember"); return attName; } private: std::string InstanceMember_; public: GetValueTypeByTag<InstanceMember>::const_ref_type getInstanceMember() const { return InstanceMember_; } GetValueTypeByTag<InstanceMember>::const_ref_type getValueByTag (InstanceMember)const {return InstanceMember_;} void setInstanceMember( GetValueTypeByTag<InstanceMember>::const_ref_type newValue) { setByTag(newValue, InstanceMember()); } protected: void setByTagImpl( GetValueTypeByTag<InstanceMember>::const_ref_type newValue, InstanceMember) { InstanceMember_ = newValue; }
public: struct ClassMember{}; template<int Dummy> struct GetNameTag<ClassMemberNum, Dummy> { typedef ClassMember type; }; template<int Dummy> struct GetValueType<ClassMemberNum, Dummy> { typedef std::string type; typedef ::boost::add_reference<std::string >::type ref_type; typedef ::boost::add_const<type>::type const_type; typedef ::boost::add_reference<const_type>::type const_ref_type; }; template<int Dummy> struct GetValueTypeByTag<ClassMember, Dummy> { typedef std::string type; typedef ::boost::add_reference<std::string >::type ref_type; typedef ::boost::add_const<type>::type const_type; typedef ::boost::add_reference<const_type>::type const_ref_type; }; template<int Dummy> struct GetMemberKind<ClassMemberNum, Dummy> { typedef refl::ClassVariableTag type; }; template<int Dummy> struct GetMemberKindByTag<ClassMember, Dummy> { typedef refl:: ClassVariableTag type; }; template<int Dummy> struct AttributePos<ClassMember, Dummy> { enum {value = ClassMemberNum}; };
static const std::string& getAttributeName(ClassMember) { static const std::string attName("ClassMember"); return attName; } private: static std::string ClassMember_; public: static GetValueTypeByTag<ClassMember>::const_ref_type getClassMember() { return ClassMember_; } static GetValueTypeByTag<ClassMember>::const_ref_type getValueByTag(ClassMember) {return ClassMember_;} public: static void setClassMember (GetValueTypeByTag<ClassMember>::const_ref_type newValue) { setByTag(newValue, ClassMember(),refl::ClassVariableTag()); } protected: static void setByTagImpl (GetValueTypeByTag<ClassMember>::const_ref_type newValue, ClassMember) { ClassMember_ = newValue; } static void setByTag(GetValueTypeByTag<ClassMember>::const_ref_type val, ClassMember, refl::ClassVariableTag) { typedef GetValueTypeByTag<ClassMember>::type MemberType; typedef GetValueTypeByTag<ClassMember>::const_ref_type SetterArgType; typedef void (*ThisStaticSetImpl)(SetterArgType,ClassMember); refl::SetWithPreAndPost<ThisClass,SetterArgType, refl::ClassVariableTag,ClassMember> wrappedSet(static_cast<ThisStaticSetImpl>(setByTagImpl),val); wrappedSet(); }
public: enum {NumAttributes =AttributeNum<endLineNo-beginLineNo>::value}; enum {NumBaseClasses=BaseClassNum<endLineNo-beginLineNo>::value}; public: template<class Tag> typename GetValueTypeByTag<Tag>::const_ref_type getValueByTag()const { return getValueByTag(Tag()); } template<class Val,class Tag> void setValueByTag(Val val, Tag tag) { setByTag(val, tag, GetMemberKindByTag<Tag>::type()); } template<class Val,class Tag> void setByTag(Val val, Tag, refl::InstanceVariableTag) { typedef typename GetValueTypeByTag<Tag>::type MemberType; typedef typename GetValueTypeByTag<Tag>::const_ref_type SetterArgType; typedef void (ThisClass::*ThisSetImpl)(SetterArgType,Tag); ThisSetImpl setImplPtr = &ThisClass::setByTagImpl; refl::SetWithPreAndPost<ThisClass,MemberType, refl::InstanceVariableTag,Tag> wrappedSet(*this, static_cast<ThisSetImpl>(&ThisClass::setByTagImpl),val); wrappedSet(); } };
Setting instance variables applies user defined pre and post operations used operations
Last revised: September 13, 2004 | Copyright © 2004 Arne Adams |