zeusUnnamed repository; edit this file 'description' to name the repository. |
git clone Unknown |
Log | Files | Refs |
visitor_template.cpp (2447B)
0 #include <iostream>
1 #include <memory>
2 #include <string>
3 #include <string_view>
4 #include <utility>
6 template <class... Types> class Visitor;
8 template <class T> class Visitor<T> {
9 public:
10 virtual void visit(T *t) = 0;
11 };
13 template <class T, class... Types>
14 class Visitor<T, Types...> : public Visitor<Types...> {
15 public:
16 using Visitor<Types...>::visit;
18 virtual void visit(T *t) = 0;
19 };
21 template <class Base, class...> class LambdaVisitor;
23 template <class Base, class T1, class F1>
24 class LambdaVisitor<Base, Visitor<T1>, F1> : private F1, public Base {
25 public:
26 LambdaVisitor(F1 &&f1) : F1(std::move(f1)) {}
27 LambdaVisitor(const F1 &f1) : F1(f1) {}
29 using Base::visit;
30 void visit(T1 *t) override { return F1::operator()(t); }
31 };
33 template <class Base, class T1, class... T, class F1, class... F>
34 class LambdaVisitor<Base, Visitor<T1, T...>, F1, F...>
35 : private F1, public LambdaVisitor<Base, Visitor<T...>, F...> {
36 using base = LambdaVisitor<Base, Visitor<T...>, F...>;
38 public:
39 LambdaVisitor(F1 &&f1, F &&...f)
40 : F1(std::move(f1)), base(std::forward<F>(f)...) {}
41 LambdaVisitor(const F1 &f1, F &&...f) : F1(f1), base(std::forward<F>(f)...) {}
43 using base::visit;
44 void visit(T1 *t) override { return F1::operator()(t); }
45 };
47 // deduction guide somehow?
48 template <typename Base, typename... F> auto lambda_visitor(F &&...f) {
49 return LambdaVisitor<Base, Base, F...>(std::forward<F>(f)...);
50 }
52 using PetVisitor = Visitor<class Cat, class Dog>;
54 class Pet {
55 std::string m_color;
57 public:
58 virtual ~Pet() = default;
59 Pet(std::string_view color) : m_color(color) {}
61 virtual void accept(PetVisitor &v) = 0;
63 const std::string &color() const { return m_color; }
64 };
66 template <class Derived> class Visitable : public Pet {
67 public:
68 using Pet::Pet;
70 void accept(PetVisitor &v) override { v.visit(static_cast<Derived *>(this)); }
71 };
73 class Cat : public Visitable<Cat> {
74 using Visitable<Cat>::Visitable;
75 };
77 class Dog : public Visitable<Dog> {
78 using Visitable<Dog>::Visitable;
79 };
81 void walk(Pet &p) {
82 auto v = lambda_visitor<PetVisitor>(
83 [](Cat *c) {
84 std::cout << "Let the " << c->color() << " cat out" << std::endl;
85 },
86 [](Dog *d) {
87 std::cout << "Let the " << d->color() << " dog out" << std::endl;
88 });
89 p.accept(v);
90 }
92 int main(void) {
93 std::unique_ptr<Pet> c(new Cat("orange"));
94 std::unique_ptr<Pet> d(new Dog("brown"));
96 walk(*c);
97 walk(*d);
99 return 0;
100 }