ANN: reflection at compiletime

A

Arne Adams

Hi all,
the current issue (Sep.04) of the CUJ has an article about my reflection library
(member variables and base classes).
Any functionality that can be defined with functions that operate on member
variables, can be implemented with the help of that library in a generic manner.
The following example from the documentation of that library is only slightly
contrived :) - more serious applications would be persistence in relational
databases, flat files, ...
This example uses the reflection macros and (which is the beef) one of the
compiletime traversions (in this case foreachAttributeInclBaseClasses) supplied
by the library

have fun,
Arne
Example
Gratifications, incentives and bonuses can come in a variety of forms. Assume
that all these can be stored as member variables (and for the sake of simplicity
all these are plain strings).

A traversion that accumulates all values that are incentives has to be able to
recognize incentives.
This can be done at compiletime using the following mapping:

struct Applies{};

struct DoesNotApply{};
template<class Tag> struct PartOfIncentiveProgram
{
typedef DoesNotApply type;
};
#define INCENTIVE_PART(Tag) \
template<> struct PartOfIncentiveProgram<Tag> \
{ \
typedef Applies type; \
};
Some personnel to populate the example:

class Employee
{
BEGIN_REFLECTION(Employee)
DEF_REFLECTED_ATTRIBUTE(std::string, BusyBee)
DEF_REFLECTED_ATTRIBUTE(short, Salary) // it's a hard world out
there :)
DEF_REFLECTED_ATTRIBUTE(std::string,Sellerie) // healthy food can
compensate a lot
// other attributes omitted :)
END_REFLECTION
virtual ~Employee(){}
};

INCENTIVE_PART(Employee::BusyBee)

class Boss : public virtual Employee
{
BEGIN_REFLECTION(Boss)
DEF_REFLECTED_VIRTUAL_BASECLASS(Employee)
DEF_REFLECTED_ATTRIBUTE(std::string, ReducedWages)
DEF_REFLECTED_ATTRIBUTE(std::string, IncreasedProduktivity)
DEF_REFLECTED_STATIC_ATTRIBUTE(std::string, ParkingLot)
// each boss has a parking lot :)
DEF_REFLECTED_ATTRIBUTE(std::vector<Employee>, Staff)
END_REFLECTION
};
INCENTIVE_PART(Boss::ReducedWages)
INCENTIVE_PART(Boss::IncreasedProduktivity)
INCENTIVE_PART(Boss::parkingLot)
// the staff does not contribute to the boss'es incentives

class ChiefTechnicalOfficer : public Boss
{
BEGIN_REFLECTION(ChiefTechnicalOfficer)
DEF_REFLECTED_VIRTUAL_BASECLASS(Boss)
DEF_REFLECTED_ATTRIBUTE(std::string, ReducedBugs)
DEF_REFLECTED_STATIC_ATTRIBUTE(std::string, FreeSoftwareBundle)
END_REFLECTION
};
INCENTIVE_PART(ChiefTechnicalOfficer::ReducedBugs)
INCENTIVE_PART(ChiefTechnicalOfficer::FreeSoftwareBundle)
The attribute function used to accumulate the incentives:

class IncentiveAccumulator
{
public:
template<class Scope, class ValueType, class NameTag>
void operator()(ValueType& attribute, NameTag nameTag, Scope* = NULL)
{
typedef typename PartOfIncentiveProgram<NameTag>::type
CouldBePartOfIncentives;
accumulateValue<Scope>(attribute, nameTag, CouldBePartOfIncentives());
}
std::string result()const
{
return incentives_.str();
}
private:
template<class Scope, class Value, class NameTag> void
accumulateValue(Value& incentive,NameTag nameTag, Applies)
{
incentives_ << Scope::getClassName() << "." <<
Scope::getAttributeName(nameTag)<< ":";
incentives_ << incentive << "\t";
}
template<class Scope, class Value, class NameTag> void
accumulateValue(Value&,NameTag, DoesNotApply)
{ }
std::stringstream incentives_;
};
For the sake of elegance:

template<class AnyOne> std::string accumulateIncentives(const AnyOne& annie)
{
IncentiveAccumulator collect;

refl::foreachAttributeInclBaseClasses(annie,collect,refl::TraverseInstanceAndCla
ssVariables());
return collect.result();
}
template<class AnyOne> std::string accumulateIncentives()
{
IncentiveAccumulator collect;
// to accumulate only the incentives that pertain to the position annie
holds:
refl::foreachAttributeInclBaseClasses<AnyOne>(collect);
return collect.result();
}
test data
std::string Boss::parkingLot_ = "a lot";
std::string ChiefTechnicalOfficer::FreeSoftwareBundle_ = "Office IP";
.. . .
ChiefTechnicalOfficer annie;
annie.setReducedWages("by 10%");
annie.setIncreasedProduktivity("by - 20%");
annie.setBusyBee("from 10 to 10");
std::cout << accumulateIncentives(annie) << '\n';
std::cout << accumulateIncentives<ChiefTechnicalOfficer>() << '\n';
output
Employee.BusyBee:from 10 to 10 Boss.ReducedWages:by 10%
Boss.IncreasedProduktivity:by - 20% Boss.ParkingLot:a lot
ChiefTechnicalOfficer.ReducedBugs:
ChiefTechnicalOfficer.FreeSoftwareBundle:Office IP

Boss.ParkingLot:a lot ChiefTechnicalOfficer.FreeSoftwareBundle:Office IP
 
D

ddddddd

just for test
Arne Adams said:
Hi all,
the current issue (Sep.04) of the CUJ has an article about my reflection library
(member variables and base classes).
Any functionality that can be defined with functions that operate on member
variables, can be implemented with the help of that library in a generic manner.
The following example from the documentation of that library is only slightly
contrived :) - more serious applications would be persistence in relational
databases, flat files, ...
This example uses the reflection macros and (which is the beef) one of the
compiletime traversions (in this case foreachAttributeInclBaseClasses) supplied
by the library

have fun,
Arne
Example
Gratifications, incentives and bonuses can come in a variety of forms. Assume
that all these can be stored as member variables (and for the sake of simplicity
all these are plain strings).

A traversion that accumulates all values that are incentives has to be able to
recognize incentives.
This can be done at compiletime using the following mapping:

struct Applies{};

struct DoesNotApply{};
template<class Tag> struct PartOfIncentiveProgram
{
typedef DoesNotApply type;
};
#define INCENTIVE_PART(Tag) \
template<> struct PartOfIncentiveProgram<Tag> \
{ \
typedef Applies type; \
};
Some personnel to populate the example:

class Employee
{
BEGIN_REFLECTION(Employee)
DEF_REFLECTED_ATTRIBUTE(std::string, BusyBee)
DEF_REFLECTED_ATTRIBUTE(short, Salary) // it's a hard world out
there :)
DEF_REFLECTED_ATTRIBUTE(std::string,Sellerie) // healthy food can
compensate a lot
// other attributes omitted :)
END_REFLECTION
virtual ~Employee(){}
};

INCENTIVE_PART(Employee::BusyBee)

class Boss : public virtual Employee
{
BEGIN_REFLECTION(Boss)
DEF_REFLECTED_VIRTUAL_BASECLASS(Employee)
DEF_REFLECTED_ATTRIBUTE(std::string, ReducedWages)
DEF_REFLECTED_ATTRIBUTE(std::string, IncreasedProduktivity)
DEF_REFLECTED_STATIC_ATTRIBUTE(std::string, ParkingLot)
// each boss has a parking lot :)
DEF_REFLECTED_ATTRIBUTE(std::vector<Employee>, Staff)
END_REFLECTION
};
INCENTIVE_PART(Boss::ReducedWages)
INCENTIVE_PART(Boss::IncreasedProduktivity)
INCENTIVE_PART(Boss::parkingLot)
// the staff does not contribute to the boss'es incentives

class ChiefTechnicalOfficer : public Boss
{
BEGIN_REFLECTION(ChiefTechnicalOfficer)
DEF_REFLECTED_VIRTUAL_BASECLASS(Boss)
DEF_REFLECTED_ATTRIBUTE(std::string, ReducedBugs)
DEF_REFLECTED_STATIC_ATTRIBUTE(std::string, FreeSoftwareBundle)
END_REFLECTION
};
INCENTIVE_PART(ChiefTechnicalOfficer::ReducedBugs)
INCENTIVE_PART(ChiefTechnicalOfficer::FreeSoftwareBundle)
The attribute function used to accumulate the incentives:

class IncentiveAccumulator
{
public:
template<class Scope, class ValueType, class NameTag>
void operator()(ValueType& attribute, NameTag nameTag, Scope* = NULL)
{
typedef typename PartOfIncentiveProgram<NameTag>::type
CouldBePartOfIncentives;
accumulateValue<Scope>(attribute, nameTag, CouldBePartOfIncentives());
}
std::string result()const
{
return incentives_.str();
}
private:
template<class Scope, class Value, class NameTag> void
accumulateValue(Value& incentive,NameTag nameTag, Applies)
{
incentives_ << Scope::getClassName() << "." <<
Scope::getAttributeName(nameTag)<< ":";
incentives_ << incentive << "\t";
}
template<class Scope, class Value, class NameTag> void
accumulateValue(Value&,NameTag, DoesNotApply)
{ }
std::stringstream incentives_;
};
For the sake of elegance:

template<class AnyOne> std::string accumulateIncentives(const AnyOne& annie)
{
IncentiveAccumulator collect;

refl::foreachAttributeInclBaseClasses(annie,collect,refl::TraverseInstanceAn
dCla
ssVariables());
return collect.result();
}
template<class AnyOne> std::string accumulateIncentives()
{
IncentiveAccumulator collect;
// to accumulate only the incentives that pertain to the position annie
holds:
refl::foreachAttributeInclBaseClasses<AnyOne>(collect);
return collect.result();
}
test data
std::string Boss::parkingLot_ = "a lot";
std::string ChiefTechnicalOfficer::FreeSoftwareBundle_ = "Office IP";
. . .
ChiefTechnicalOfficer annie;
annie.setReducedWages("by 10%");
annie.setIncreasedProduktivity("by - 20%");
annie.setBusyBee("from 10 to 10");
std::cout << accumulateIncentives(annie) << '\n';
std::cout << accumulateIncentives<ChiefTechnicalOfficer>() << '\n';
output
Employee.BusyBee:from 10 to 10 Boss.ReducedWages:by 10%
Boss.IncreasedProduktivity:by - 20% Boss.ParkingLot:a lot
ChiefTechnicalOfficer.ReducedBugs:
ChiefTechnicalOfficer.FreeSoftwareBundle:Office IP

Boss.ParkingLot:a lot ChiefTechnicalOfficer.FreeSoftwareBundle:Office IP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top