// Example program
#include <iostream>
#include <string>
template < class Derived, class TBase> class Skill1a : TBase
{
public:
enum { HAS_SKILL1 = 1 };
int foo1() const { return 1; }
};
template < class Derived, class TBase> class Skill1b : TBase
{
public:
enum { HAS_SKILL1 = 1 };
int foo1() const { return -1; }
};
template < class Derived, class TBase > class Skill2 : TBase
{
public:
enum { SKILL2_REQUIRES_SKILL1 = TBase::HAS_SKILL1 };
enum { HAS_SKILL2 = 1 };
// add a feature:
int foo2() const { return TBase::foo1() * 2; }
// overload a base feature: (optional)
int foo1() const { return TBase::foo1()+10; }
};
struct EmptyBaseClass {};
template<class Derived,
template <class,class> class... Bases>
struct make_base;
template<class Derived,
template <class,class> class Base>
struct make_base<Derived,Base> {
typedef Base<Derived,EmptyBaseClass > type;
};
template<class Derived,
template <class,class> class... Bases,
template <class,class> class Base0>
struct make_base<Derived,Base0,Bases...> {
typedef Base0<Derived,typename make_base<Derived,Bases...>::type> type;
};
template< template <class,class> class... Bases>
struct Thing : public make_base<Thing<Bases...>,Bases...>::type
{
using Base = typename make_base<Thing,Bases...>::type;
};
int main()
{
Thing<Skill1a> a;
Thing<Skill1b> b;
Thing<Skill2,Skill1a> c;
std::cout << a.foo1() << std::endl;
std::cout << b.foo1() << std::endl;
std::cout << c.foo2() << std::endl;
std::cout << c.foo1() << std::endl;
// Thing<Skill2> compile_error;
//
// main.cpp:25:8: error: 'HAS_SKILL1' is not a member of 'EmptyBaseClass'
// enum { SKILL2_REQUIRES_SKILL1 = TBase::HAS_SKILL1 };
// ^
}