Suppose you have some classes like Circle, Image, Polygon for which you need to enforce a common interface that looks like this (not real code):
struct Interface {
virtual bool hitTest(Point p) = 0;
virtual Rect boundingRect() = 0;
virtual std::string uniqueId() = 0;
}
so for example the Circle class would like:
struct Circle {
// interface
bool hitTest(Point p) override;
Rect boundingRect() override;
std::string uniqueId() override;
double radius() const;
Point center() const;
// other stuff
}
I would like to use std::variant<Circle, Image, Polygon> to store instances of my classes in a std::vector and then use it like this:
using VisualElement = std::variant<Circle, Image, Polygon>;
std::vector<VisualElement> elements;
VisualElement circle = MakeCircle(5, 10);
VisualElement image = MakeImage("path_to_image.png");
elements.push_back(circle);
elements.push_back(image);
auto const &firstElement = elements[0];
std::cout << firstElement.uniqueId() << std::endl;
Using inheritance I could do this by creating a base class and then each of my classes would become a subclass of the base (and obviously if a derive class doesn't implement the interface the program wouldn't compile). Then instead of using variants, I could use smart pointers to store the instances in a vector (e.g. std::vector<std::unique_ptr<BaseElement>>). I would like to avoid this, so I'm wondering what would be the best way (if there is any) to enforce the same design using std::variant and C++20.
std::vector<std::variant<A, B, C>>I suggest having vectors per type for data homogeneity. I.e. you will havestd::tuple<std::vector<A>, std::vector<B>, std::vector<C>>and with some helper code you can pick from the correct vector depending on what you're working with. The code will run much faster if you don't need to check the type for every single entry.