Created
December 31, 2022 18:37
-
-
Save ghamarian/4feb867f9ad40b656f531f1063d9b62c to your computer and use it in GitHub Desktop.
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 <algorithm> | |
#include <concepts> | |
#include <functional> | |
#include <iostream> | |
#include <memory> | |
#include <vector> | |
template <typename T> | |
concept Drawable = requires(T t) { | |
{ t.draw() } -> std::same_as<void>; | |
{ t.name() } -> std::same_as<std::string>; | |
}; | |
// A type-erased wrapper for any object that has a "draw" method | |
class shape { | |
public: | |
// Construct a shape from any object that has a "draw" method | |
template <Drawable T> | |
shape(T &&t) | |
: impl_(std::make_unique<impl<std::decay_t<T>>>(std::forward<T>(t))) {} | |
// Invoke the "draw" method on the wrapped object | |
void draw() { impl_->draw(); } | |
std::string name() { return impl_->name(); } | |
private: | |
// A base class for the type-erased implementation | |
struct impl_base { | |
virtual void draw() = 0; | |
virtual std::string name() = 0; | |
virtual ~impl_base() {} | |
}; | |
// A concrete implementation for a specific type T | |
template <Drawable T> struct impl : impl_base { | |
impl(T t) : obj_(std::move(t)) {} | |
void draw() override { obj_.draw(); } | |
std::string name() override { return obj_.name(); } | |
T obj_; | |
}; | |
std::unique_ptr<impl_base> impl_; | |
}; | |
// Example objects that can be type-erased | |
struct circle { | |
void draw() { std::cout << "Drawing a circle" << std::endl; } | |
std::string name() { return "Fancy circle"; } | |
}; | |
struct square { | |
void draw() { std::cout << "Drawing a square" << std::endl; } | |
std::string name() { return "Fancy square"; } | |
}; | |
int main() { | |
// Create a shape from a circle and draw it | |
shape s1(circle{}); | |
s1.draw(); | |
// Create a shape from a square and draw it | |
shape s2(square{}); | |
s2.draw(); | |
auto q = std::make_unique<shape>(square{}); | |
auto p = std::make_unique<shape>(circle{}); | |
auto z = std::make_unique<shape>(square{}); | |
// one square | |
std::vector<std::unique_ptr<shape>> shapes; | |
shapes.emplace_back(std::move(p)); | |
shapes.emplace_back(std::move(q)); | |
shapes.emplace_back(std::move(z)); | |
// call draw on the shapes | |
// std::for_each(shapes.begin(), shapes.end(), [](auto &s) { std::cout << | |
// s->name() << std::endl; }); replace this for each go over the shapes | |
for (const auto &s : shapes) { | |
std::cout << s->name() << std::endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment