Basic Usage

Example

class ExampleBase
{
    BEGIN_REFLECTION(ExampleBase)
    DEF_REFLECTED_ATTRIBUTE(int, BaseMember) 
    END_REFLECTION 
};
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 
}; 

std::string Example::ClassMember_= "classmember"; 
. . .
Example example; 
refl::PrintRecord printer(std::cout);
printer.print(example); 
example.setInstanceMember("instance member"); 
example.setBaseMember(23); 
example.setClassMember("clazz mamba"); 
std::cout<< refl::getRecordDesc(example) << "\n"; 
std::set<Example,RecordIsLess<Example> > sortedExamples; 

the output of these statements is:
ExampleBase: BaseMember: 0; Example: InstanceMember: ; ClassMember: class member;

ExampleBase: BaseMember: 23; Example: InstanceMember: instance member; ClassMember: clazz mamba;

Intended as tracing utility this library has a template class PrintRecord. The compiler generated instantion of the print member function of this class iterates over all reflected members and base classes and prints their representation on an ostream&. The template function getRecordDesc uses PrintRecord with a stringstream to produce a string representation of a reflected class instance.
Apart from that, PrintRecord shows the usage of a generative algorithm in the reflection library: depthFirstForeachIncAllBaseClasses.

Note that BaseMember was 0 in contrast to an unitialized int - that is so because BEGIN_REFLECTION defines a default constructor that default initializes all POD (plain old data) members in its body.

RecordIsLess is a predefined function object that does lexicographical comparison on the set of all attributes of a reflected class.

The main purpose of this library is to facilitate the definition of generative algorithms (like RecordIsLess, PrintRecord). The object graph traversions in the library make it possible for instance to define a declarative persistence mapping in databases, serialization in different fileformats, and in general: any functionality that can be defined on subsets of member variables of classes.
To achieve that, the user has to define an attribute function object, that specifies what has to happen with leafs in the object graph that is spanned by the reflected members of a class.

Accessors

To get values of member variables the following statements are valid:
(due to built in limitations some notations are not available in VC6 and some statements need a different syntax for that compiler):

std::string firstAttribute = example.getInstanceMember();
firstAttribute = example.getValueByTag(Example::InstanceMember());
The following statement won't compile with VC6: firstAttribute = example.getValueByTag<Example::InstanceMember>();

AttributeTag by Index

typedef Example::GetNameTag<0>::type FirstAttributeTag;
For VC6 you will have to use this form: typedef Example::GetNameTag<0, Example::ThisClass>::type FirstAttributeTag;
In both statements FirstAttributeTag will be an alias for the type Example::InstanceMember

firstAttribute = example.getValueByTag(FirstAttributeTag());
The following statement won't compile with VC6: firstAttribute = example.getValueByTag<FirstAttributeTag>();

ValueType by Index

typedef Example::GetValueType<0>::type FirstAttributeType;
For VC6 you will have to use this form: typedef Example::GetValueType<0, Example::ThisClass>::type FirstAttributeType;
In both statements FirstAttributeType will be an alias for the typedef std::string

ValueType by Tag

typedef Example::GetValueTypeByTag<Example::InstanceMember>::type FirstAttributeTypeAgain;
For VC6 you will have to use this form:
typedef Example::GetValueTypeByTag<Example::InstanceMember,Example::ThisClass>::type FirstAttributeTypeAgain;
In both statements FirstAttributeTypeAgain will be an alias for the typedef std::string

Member Number by Tag

enum {firstAttributePos = Example::AttributePos<Example::InstanceMember>::value};
For VC6 you will have to use this form:
enum {firstAttributePos = Example::AttributePos<Example::InstanceMember,Example::ThisClass>::value};
In both statements firstAttributePos will have the value 0.

Similar statements are valid for static member variables and in addition the following:
std::string secondAttribute = Example::getClassMember();

Setter

To set values of member variables the following statements are valid:

std::string newValue = "tralalala";
example.setInstanceMember(newValue);
example.setValueByTag(newValue, Example::InstanceMember());
Example::setClassMember(newValue);
example.setClassMember(newValue);
example.setValueByTag(newValue, Example::ClassMember());

Detecting whether a member variable is static or not

typedef Example::GetMemberKind<0>::type FirstAttributeKind;
typedef Example::GetMemberKindByTag<Example::InstanceMember>::type FirstAttributeKindAgain;
For VC6 you will have to use this form: typedef Example::GetMemberKind<0,Example::ThisClass>::type FirstAttributeKind;
typedef Example::GetMemberKindByTag<Example::InstanceMember Example::ThisClass>::type FirstAttributeKindAgain;
In the preceding 4 statements FirstAttributeKind will be an alias for the type refl::InstanceVariableTag

typedef Example::GetMemberKind<1>::type SecondAttributeKind;
typedef Example::GetMemberKindByTag<Example::ClassMember>::type SecondAttributeKindAgain;
For VC6 you will have to use this form: typedef Example::GetMemberKind<1,Example::ThisClass>::type SecondAttributeKind;
typedef Example::GetMemberKindByTag<Example::ClassMember,Example::ThisClass>::type SecondAttributeKindAgain;
In the preceding 4 statements FirstAttributeKind will be an alias for the type refl::ClassVariableTag

Hacked printf at compiletime

FirstAttributeKind::hans();
Visual C++ displays a compiler error like this: hans is not a member of refl::InstanceVariableTag
SecondAttributeKindAgain::theo();
Visual C++ displays a compiler error like this: theo is not a member of refl::ClassVariableTag

Accessing base classes through reflection

typedef Example::GetBaseClass<0>::type ZeBase;
For VC6 you will have to use this form: typedef Example::GetBaseClass<0, Example::ThisClass>::type ZeBase;
In both statements ZeBase will be an alias for the type ExampleBase

Determine whether a direct base is virtual

enum {zeBaseIsVirtuallyInherited = Example::GetBaseClass<0>::isVirtual};
For VC6 you will have to use this form: enum {zeBaseIsVirtuallyInherited = Example::GetBaseClass<0, Example::ThisClass >::isVirtual};
In both statements zeBaseIsVirtuallyInherited will have the value 1.

Diagnostic messages generated by the Library

typedef Example::GetNameTag<2>::type OffByOne;
OffByOne what;
On Visual C++ this yields a compiler error containing the tokens:
Example::ERROR_ERROR_ERROR_not_a_valid_tag_position_ERROR_END.

typedef Example::GetValueTypeByTag <int>::type InvalidTagType;
InvalidTagType errorAgain;
On Visual C++ this yields a compiler error containing the tokens:
Example::ERROR_ERROR_ERROR_not_a_valid_tag_ERROR_END.

typedef Example::GetBaseClass<1>::type OffByOneAgain;
OffByOneAgain anotherError;
On Visual C++ this yields a compiler error containing the tokens:
Example::ERROR_ERROR_ERROR_not_a_valid_baseclass_num_ERROR_END

Getting the count of reflected entities

The macros that define reflection define a compile-time program that calculates the number of reflected attributes and the number of reflected base classes.
These values are accessible as compiletime constants in the scope of the enclosing class.
enum {examplesAttributeCount = Example::NumAttributes};
enum {examplesBaseClassCount = Example::NumBaseClasses};
here the value of examplesAttributeCount will be 2 and the value of examplesBaseClassCount will be 1 (for the latter only the direct base classes are counted).

Last revised: September 13, 2004 Copyright 2004 Arne Adams