More C++ Idioms/Hierarchy Generation
Appearance
Hierarchy Generation
[edit | edit source]Intent
[edit | edit source]To generate a concrete class composed to various behavioral policies
Also Known As
[edit | edit source]Motivation
[edit | edit source]When a solution calls for a number of different implementations that can be combine in a variety of ways, each sharing or not sharing various decorations, the traditional solution is multiple inheritance which produces a variety of problems. Hierarchy generation is a pattern by which a variety of base classes are successively inherited to avoid multiple inheritance.
Solution and Sample Code
[edit | edit source]#include <iostream>
//prototype
template <template <class> class ... _PolicyTs> struct GenHierarchy;
//specialization for N policies constructs inheritance hierarchy
template <template <class> class _HeadPolicyT, template <class> class ... _TailPolicyTs>
struct GenHierarchy<_HeadPolicyT, _TailPolicyTs...> : _HeadPolicyT < GenHierarchy<_TailPolicyTs...> > {};
//inheritance hierarchy terminator and base class for concrete implementations
template <> struct GenHierarchy < > {};
//dance behavior policies
template <typename _ParentT> struct DanceA : _ParentT{
void Dance(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct DanceB : _ParentT{
void Dance(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct DanceC : _ParentT{
void Dance(){ std::cout << __FUNCTION__ << std::endl; }
};
//joke behavior policies
template <typename _ParentT> struct JokeA : _ParentT{
void Joke(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct JokeB : _ParentT{
void Joke(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct JokeC : _ParentT{
void Joke(){ std::cout << __FUNCTION__ << std::endl; }
};
//sing behavior policies
template <typename _ParentT> struct SongA : _ParentT{
void Sing(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct SongB : _ParentT{
void Sing(){ std::cout << __FUNCTION__ << std::endl; }
};
template <typename _ParentT> struct SongC : _ParentT{
void Sing(){ std::cout << __FUNCTION__ << std::endl; }
};
//combine some behavior policies into concrete types
using BozoTheClown = GenHierarchy < DanceA, JokeB, SongC > ;
using HowdyDoody = GenHierarchy < DanceB, JokeA, SongA > ;
using RedButtons = GenHierarchy < DanceC, JokeC, SongB > ;
template <typename _Ty> void Entertain(_Ty oEntertainer){
oEntertainer.Sing();
oEntertainer.Dance();
oEntertainer.Joke();
}
int main(){
Entertain(BozoTheClown());
Entertain(HowdyDoody());
Entertain(RedButtons());
return 0;
}
In the above example the BozoTheClown declaration is a short hand of effectively the following:
struct BozoTheClown : DanceA<JokeB<SongC<GenHierarchy<>>>>{};
This is identical to:
struct GenHierarchy{};
struct SongC : GenHierarchy{ void Sing(){ std::cout << __FUNCTION__ << std::endl; } };
struct JokeB : SongC{ void Joke(){ std::cout << __FUNCTION__ << std::endl; } };
struct DanceA : JokeB{ void Dance(){ std::cout << __FUNCTION__ << std::endl; } };
struct BozoTheClown : DanceA{};
The behavior policies must follow this concept:
template <typename _ParentT> struct Base : _ParentT