Macros to define reflected entities

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).

Reflection macros expanded

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).

BEGIN_REFLECTION

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.

DEF_REFLECTED_VIRTUAL_BASECLASS

    template<int Dummy> struct GetBaseClass<ExampleBaseNum, Dummy> 
    { 
        typedef ExampleBase type; 
        enum { isVirtual = true}; 
    }; 
            
The value of ExampleBaseNum is 0.

DEF_REFLECTED_ATTRIBUTE

    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}; 
    }; 
            
Where InstanceMemberNum == 0.
    
    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; 
    } 
            

DEF_REFLECTED_STATIC_ATTRIBUTE

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}; 
    }; 
			
Where ClassMemberNum == 1
    
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();                                                
    }                                                                
		

END_REFLECTION

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