zeus

Unnamed repository; edit this file 'description' to name the repository.
git clone Unknown
Log | Files | Refs

commit ca88f900f3fb64f5482e84530cf599ec68dbc0e8
parent 37ffe2c5a7871bd8d0463b4d2b35ce16377f1c30
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Sun, 18 May 2025 21:27:31 +0200

Template version of visitor patterns

Diffstat:
A visitor_template.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A visitor_template_acyclic.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2 files changed, 183 insertions(+), 0 deletions(-)


diff --git a/ visitor_template.cpp b/ visitor_template.cpp

@@ -0,0 +1,101 @@

#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <utility>

template <class... Types> class Visitor;

template <class T> class Visitor<T> {
public:
virtual void visit(T *t) = 0;
};

template <class T, class... Types>
class Visitor<T, Types...> : public Visitor<Types...> {
public:
using Visitor<Types...>::visit;

virtual void visit(T *t) = 0;
};

template <class Base, class...> class LambdaVisitor;

template <class Base, class T1, class F1>
class LambdaVisitor<Base, Visitor<T1>, F1> : private F1, public Base {
public:
LambdaVisitor(F1 &&f1) : F1(std::move(f1)) {}
LambdaVisitor(const F1 &f1) : F1(f1) {}

using Base::visit;
void visit(T1 *t) override { return F1::operator()(t); }
};

template <class Base, class T1, class... T, class F1, class... F>
class LambdaVisitor<Base, Visitor<T1, T...>, F1, F...>
: private F1, public LambdaVisitor<Base, Visitor<T...>, F...> {
using base = LambdaVisitor<Base, Visitor<T...>, F...>;

public:
LambdaVisitor(F1 &&f1, F &&...f)
: F1(std::move(f1)), base(std::forward<F>(f)...) {}
LambdaVisitor(const F1 &f1, F &&...f) : F1(f1), base(std::forward<F>(f)...) {}

using base::visit;
void visit(T1 *t) override { return F1::operator()(t); }
};

// deduction guide somehow?
template <typename Base, typename... F> auto lambda_visitor(F &&...f) {
return LambdaVisitor<Base, Base, F...>(std::forward<F>(f)...);
}

using PetVisitor = Visitor<class Cat, class Dog>;

class Pet {
std::string m_color;

public:
virtual ~Pet() = default;
Pet(std::string_view color) : m_color(color) {}

virtual void accept(PetVisitor &v) = 0;

const std::string &color() const { return m_color; }
};

template <class Derived> class Visitable : public Pet {
public:
using Pet::Pet;

void accept(PetVisitor &v) override { v.visit(static_cast<Derived *>(this)); }
};

class Cat : public Visitable<Cat> {
using Visitable<Cat>::Visitable;
};

class Dog : public Visitable<Dog> {
using Visitable<Dog>::Visitable;
};

void walk(Pet &p) {
auto v = lambda_visitor<PetVisitor>(
[](Cat *c) {
std::cout << "Let the " << c->color() << " cat out" << std::endl;
},
[](Dog *d) {
std::cout << "Let the " << d->color() << " dog out" << std::endl;
});
p.accept(v);
}

int main(void) {
std::unique_ptr<Pet> c(new Cat("orange"));
std::unique_ptr<Pet> d(new Dog("brown"));

walk(*c);
walk(*d);

return 0;
}

diff --git a/ visitor_template_acyclic.cpp b/ visitor_template_acyclic.cpp

@@ -0,0 +1,82 @@

#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>

class VisitorBase {
public:
virtual ~VisitorBase() = default;
};

template <class Visitable> class Visitor {
public:
virtual void visit(Visitable *p) = 0;
};

template <typename... V> struct Visitors;

template <typename V1>
struct Visitors<V1> : public VisitorBase, public Visitor<V1> {};

template <typename V1, typename... V>
struct Visitors<V1, V...> : public Visitor<V1>, public Visitors<V...> {};

template <typename Base, typename Visitable> class VisitableBase : public Base {
public:
using Base::Base;

void accept(VisitorBase &v) override {
if (Visitor<Visitable> *pv = dynamic_cast<Visitor<Visitable> *>(&v)) {
pv->visit(static_cast<Visitable *>(this));
} else {
assert(false);
}
}
};

class Pet {
std::string m_color;

public:
virtual ~Pet() = default;
Pet(std::string_view color) : m_color(color) {}

virtual void accept(VisitorBase &v) = 0;

const std::string &color() const { return m_color; }
};

template <class Visitable> using PetVisitable = VisitableBase<Pet, Visitable>;

class Cat : public PetVisitable<Cat> {
public:
using PetVisitable<Cat>::PetVisitable;
};

class Dog : public PetVisitable<Dog> {
public:
using PetVisitable<Dog>::PetVisitable;
};

class FeedingVisitor : public Visitors<Cat, Dog> {
public:
void visit(Cat *c) override {
std::cout << "Feed tuna to the " << c->color() << " cat\n";
}

void visit(Dog *c) override {
std::cout << "Feed streak to the " << c->color() << " dog\n";
}
};

int main() {
std::unique_ptr<Pet> c(new Cat("orange"));
std::unique_ptr<Pet> d(new Dog("brown"));

FeedingVisitor fv;
c->accept(fv);
d->accept(fv);

return 0;
}