Last active
December 15, 2021 11:16
-
-
Save SanderMertens/b380ab1a9caf8ab0f3e9e2e72f454885 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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