Skip to content

Instantly share code, notes, and snippets.

@SanderMertens
Last active December 15, 2021 11:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SanderMertens/b380ab1a9caf8ab0f3e9e2e72f454885 to your computer and use it in GitHub Desktop.
Save SanderMertens/b380ab1a9caf8ab0f3e9e2e72f454885 to your computer and use it in GitHub Desktop.
// Utility for adding features (mixins) to a class without modifying its
// definition.
// -- Mixin code
// Create macro for mixin template type so we don't go cross-eyed
#define MIXIN template<typename Self> typename
// Template that can store a list of mixin templates
template< MIXIN ... Mixin>
struct mixin_list { };
// Used for last element in mixins list (see next)
template <typename T, typename Mixin>
struct mixins { };
// Recursively unpack the elements in the mixin list. Add current mixin as base
// base class, wrap remaining mixins in a new list & pass to self.
template <typename T, MIXIN Mixin, MIXIN ... Mixins>
struct mixins<T, mixin_list<Mixin, Mixins...> > : Mixin<T>, mixins<T, mixin_list< Mixins... >> { };
// Base class for mixin implementations. The virtual method provides access to
// the instance of the top-level type.
template <typename Self>
struct mixin {
protected:
virtual Self& self() = 0;
};
// Base for extendable class. Accepts own type and list of mixins
template <typename T, typename Mixins>
struct extendable : mixins<T, Mixins> {
T& self() {
return *static_cast<T*>(this);
}
};
// -- User code
// Example mixin implementation #1
template <typename T>
struct movable : mixin<T> {
void move(int x, int y) {
this->self().x_ = x;
this->self().y_ = y;
}
};
// Example mixin implementation #2
template <typename T>
struct feedable : mixin<T> {
void feed(int food) {
this->self().hunger_ -= food;
}
};
// List with both mixins
using Mixins = mixin_list<movable, feedable>;
// Extendable class implementation
struct dog : extendable<dog, Mixins> {
int x_ = 0;
int y_ = 0;
int hunger_ = 100;
};
int main() {
dog d;
d.move(10, 20); // call from mixin movable
d.feed(40); // call from mixin feedable
printf("position = %d, %d\n", d.x_, d.y_); // 10, 20
printf("hunger = %d\n", d.hunger_); // 60
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment