ANN: reflection at compiletime

  • Follow


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



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Arne 7/28/2004 3:39:27 PM

ooops- the library is available at:
http://www.cuj.com/code/
and at:
http://www.arneadams.com/

-- 
Regards,

Arne



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Arne 7/28/2004 4:09:58 PM


just for test
"Arne Adams" <arne.adams@t-online.de> wrote in message
news:ce8er6$lr9$03$1@news.t-online.com...
> 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
>
>
>
>       [ See http://www.gotw.ca/resources/clcm.htm for info about ]
>       [ comp.lang.c++.moderated.    First time posters: Do this! ]





0
Reply abc125 (72) 7/29/2004 8:07:26 AM

ddddddd wrote:

> just for test

Use alt.test for testing.

-- 
Peter van Merkerk
peter.van.merkerk(at)dse.nl
0
Reply merkerk (462) 7/29/2004 8:19:58 AM

3 Replies
77 Views

(page loaded in 0.016 seconds)


Reply: