#include <type_traits>
using std::tr1::is_base_of;
// --- policy metaprogramming ---
// classes marked with (derived from) chaining_tag
// must have template member 'with'
struct chaining_tag{};
// metafunction, returns type derived from all the items listed
// usage example: chain<X, Y>::type
template <class T, class U,
bool supports_chaining = is_base_of<chaining_tag, T>::value,
bool reverse_chaining = is_base_of<chaining_tag, U>::value>
struct chain;
template <class T, class U, bool free_>
struct chain<T, U, true, free_>{
typedef typename T::template with<U>::type type;
};
template <class T, class U>
struct chain<T, U, false, true>{
typedef typename U::template with<T>::type type;
};
template <class T, class U>
struct chain<T, U, false, false>{
struct with_ : T, U {};
typedef with_ type;
};
// --- example class using policy chaining
template <class Allocator, class ThreadingPolicy, class KitchenSinkPolicy>
struct Something
{
typedef
typename chain<
typename chain<
Allocator,
ThreadingPolicy
>::type,
KitchenSinkPolicy
>::type
all_policies;
all_policies policies_;
};
// --- some policies to instantiate with ---
struct myalloc{
void alloc(){}
};
template <class ChainedBase = chaining_tag>
struct mythreading_ : ChainedBase {
template <class T>
struct with{ typedef mythreading_<T> type; };
void lock(){}
};
typedef mythreading_<> mythreading;
template <class ChainedBase = chaining_tag>
struct mykitchensink_ : ChainedBase {
template <class T>
struct with{ typedef mykitchensink_<T> type; };
void water(){}
};
typedef mykitchensink_<> mykitchensink;
// -- example code accessing the all_policies chained object
int main(){
Something<myalloc, mythreading, mykitchensink> something;
something.policies_.alloc();
something.policies_.lock();
something.policies_.water();
}