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