Last active
October 17, 2018 17:25
-
-
Save langthom/c1a13710bb61f92649822e53ea676b09 to your computer and use it in GitHub Desktop.
Exemplary demonstration of how Mixins could be implemented in C++.
This file contains hidden or 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
// Simple mixins in C++. Thomas Lang, 2018. | |
#include <iostream> | |
#include <list> | |
namespace { | |
// add const reference to type. | |
template<typename T> | |
struct add_cref : std::add_lvalue_reference<std::add_const<T> > {}; | |
// calculate F /\ G | |
template<bool F, bool G> | |
struct AND : std::false_type {}; | |
template<> | |
struct AND<true, true> : std::true_type {}; | |
} | |
// Base class, a simple queue with no special features. | |
template<typename ElementType> | |
class BaseQueue { | |
protected: | |
typedef ElementType ArgumentType; | |
public: | |
BaseQueue() = default; | |
~BaseQueue() = default; | |
ElementType pop(void) { | |
ElementType frontCopy = *_queue.begin(); | |
_queue.pop_front(); | |
return frontCopy; | |
} | |
virtual void push(ElementType arg) { | |
_queue.push_back(arg); | |
} | |
template<typename T> | |
friend std::ostream& operator<<(std::ostream&, const BaseQueue<T>&); | |
private: | |
std::list<ElementType> _queue; | |
}; | |
template<typename ElementType> | |
std::ostream& operator<<(std::ostream& out, const BaseQueue<ElementType>& queue) { | |
out << "["; | |
for (auto it = queue._queue.begin(); it != queue._queue.end(); ++it) { | |
if (it != queue._queue.begin()) out << ","; | |
out << *it; | |
} | |
out << "]"; | |
return out; | |
} | |
// Feature #1: Increment each value by 1 on pushing. | |
template<typename Base> | |
class Incrementing : public Base { | |
public: | |
virtual void push(typename Base::ArgumentType arg) override { | |
arg += 1; | |
Base::push(arg); | |
} | |
}; | |
// Feature #2: Double each value on pushing. | |
template<typename Base> | |
class Doubling : public Base { | |
public: | |
virtual void push(typename Base::ArgumentType arg) override { | |
arg *= 2; | |
Base::push(arg); | |
} | |
}; | |
int main(void) { | |
BaseQueue<int> base; // A regular queue. | |
Incrementing<BaseQueue<int>> incr; // A queue with the incrementing feature | |
Doubling<Incrementing<BaseQueue<int> > > sepp1; // A queue with incrementing and doubling feature. | |
Incrementing<Doubling<BaseQueue<int> > > sepp2; // A queue with doubling and incrementing feature. | |
for (unsigned int i = 0; i < 4; ++i) { | |
base.push(i); | |
incr.push(i); | |
sepp1.push(i); | |
sepp2.push(i); | |
} | |
std::cout << "Base queue: (\\i -> i) " << base << std::endl; | |
std::cout << "Incrementor queue: (\\i -> i + 1) " << incr << std::endl; | |
std::cout << "complex1 queue: (\\i -> 2*i + 1) " << sepp1 << std::endl; | |
std::cout << "complex2 queue: (\\i -> (i+1) * 2) " << sepp2 << std::endl; | |
std::cout << std::endl; | |
// ------------------------- | |
for (unsigned int i = 0; i < 3; ++i) { | |
base.pop(); | |
incr.pop(); | |
sepp1.pop(); | |
sepp2.pop(); | |
} | |
std::cout << "Popping 3 times, result: (base) " << base << std::endl; | |
std::cout << "Popping 3 times, result: (incr) " << incr << std::endl; | |
std::cout << "Popping 3 times, result: (sepp1) " << sepp1 << std::endl; | |
std::cout << "Popping 3 times, result: (sepp2) " << sepp2 << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment