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: June 14, 2004 | Copyright © 2004 Arne Adams |