zeusUnnamed 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
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;
}