In modern C++17, the Visitor pattern can be implemented without traditional class hierarchies or virtual functions by using std::variant to represent a type-safe union of possible types and std::visit to apply a visitor functor.
This approach follows the Open-Closed Principle more effectively because the data classes (e.g., Food, Drink) do not need to inherit from a base class or implement an AcceptVisitor method. This allows you to add new types to the std::variant or new visitors without modifying the existing data structures.
// 1. Define data structures
class Food { /* ... */ };
class Drink { /* ... */ };
// 2. Create a variant union of all possible types
using Item = std::variant<Food, Drink>;
using Menu = std::vector<Item>;
// 3. Create a visitor functor with overloaded operator()
class Serialiser {
public:
void operator()(Food const &food) const { /* handle food */ }
void operator()(Drink const &drink) const { /* handle drink */ }
};
// 4. Apply the visitor using std::visit
Menu menu;
menu.emplace_back(Food{"Borscht", 160, Food::Label::meat});
std::visit(Serialiser{}, menu[0]);