Skip to content

Instantly share code, notes, and snippets.

@Vermeille
Created November 14, 2017 14:09
Show Gist options
  • Save Vermeille/426304e731af86796effd3a0cb8584c8 to your computer and use it in GitHub Desktop.
Save Vermeille/426304e731af86796effd3a0cb8584c8 to your computer and use it in GitHub Desktop.
structural polymorphism in C++
#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