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:arkingLot)
// 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:arkingLot_ = "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
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:arkingLot)
// 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:arkingLot_ = "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