Created
November 14, 2017 14:09
-
-
Save Vermeille/426304e731af86796effd3a0cb8584c8 to your computer and use it in GitHub Desktop.
structural polymorphism 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
#include <iostream> | |
#include <memory> | |
#include <vector> | |
/* | |
* This snippet is demonstrating a powerful technique enabling local and | |
* concept-based polymorphism. Think of it as interfaces on steroids: | |
* They're local, non intrusive, which means you don't have to think of them | |
* ahead, they don't make virtual calls when you don't want to use them, etc. | |
* | |
* Those are kinda one shot local interface inheritance and polymorphism. | |
* | |
* With black magic, it's even possible to reunite with the same interface | |
* different functions, like reunite Print(), Show(), operator<<() under a | |
* Printable trait. But those are dark arcanes that can be used only by | |
* summoning Cthulhu and that I'd explain only if asked. | |
* | |
* In the same way, with some more black magic, the boiler plate code can be | |
* reduced, but your soul has to be sold to Satan AND Cthulhu AND Quetzacoatl. | |
* With a sample of your blood. (Or you can use macros, which just requires to | |
* give up on your dignity) | |
* | |
* Credits: Sean Parent. | |
*/ | |
// Our toy classes. No common interface. | |
struct A { | |
void Print() const { std::cout << "I'm A!\n"; } | |
}; | |
struct B { | |
void Print() const { std::cout << "I'm B!\n"; } | |
}; | |
// Our trait: | |
struct Printable { | |
template <class T> | |
Printable(T&& x) | |
: base_(std::make_unique<Printable_<T>>(std::forward<T>(x))) {} | |
void Print() const { base_->Print(); } | |
struct Base { | |
virtual void Print() const = 0; | |
}; | |
template <class T> | |
struct Printable_ : public Base { | |
template <class U> | |
Printable_(U&& x) : x_(std::forward<U>(x)) {} | |
void Print() const override { x_.Print(); } | |
T x_; | |
}; | |
std::unique_ptr<Base> base_; | |
}; | |
int main() { | |
// Tadaaam, store them in a vec as if they both inherited from the same | |
// interface. | |
std::vector<Printable> ps; | |
ps.emplace_back(A()); | |
ps.emplace_back(A()); | |
ps.emplace_back(A()); | |
ps.emplace_back(B()); | |
ps.emplace_back(B()); | |
ps.emplace_back(A()); | |
for (auto& p : ps) { | |
p.Print(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment