I'd like to implement a fully generic Visitor pattern using >= C++14 using template metaprogramming. I've already found a nice way to generalize the Visitor itself, but I'm having trouble defining the Visitables. The code below works, but I'd like the commented out code in main
to work as well; in particular, I want to be able to have a collection of Visitables and apply a Visitor to each element.
Is what I'm trying to do even possible in C++?
Things I've tried:
class X : public Visitable<X>
This solves the problem of not having a suitableaccept
method inX
, but results in ambiguitiesX/A
andX/B
which the compiler cannot resolve.- empty
accept
method inX
without inheriting; works, but the specializedaccept
methods inA
andB
are never called. - replace template class
Visitor
with regular class with function templatevisit
for arbitrary types; does not really change the semantics, but is less readable IMHO
#include <iostream>
#include <vector>
template <typename I>
class Visitable {
public:
template <typename Visitor>
void accept(Visitor&& v) const {
v.visit(static_cast<const I&>(*this));
}
};
template <typename T, typename... Ts>
class Visitor : public Visitor<Ts...> {
public:
virtual void visit(const T& t);
};
template<typename T>
class Visitor<T> {
public:
virtual void visit(const T& t);
};
struct X {
// template <typename V> void accept(V&& v) const {};
};
struct A : public X, public Visitable<A> {};
struct B : public X, public Visitable<B> {};
class MyVisitor : public Visitor<A, B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
// std::vector<X> elems { A(), B() };
// for (const auto& x : elems) {
// x.accept(v);
// }
A().accept(v);
B().accept(v);
}
Aucun commentaire:
Enregistrer un commentaire