More C++ Idioms/Hierarchy Generation

Hierarchy Generation

edit

Intent

edit

To generate a concrete class composed to various behavioral policies

Also Known As

edit

Motivation

edit

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
#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