Implement the "visitor pattern" with templates - c++

I'm trying to implement a modified version of the visitor pattern in a parametric manner, avoiding in this way a "universal visitor" with a overload for each concrete element, but, due to I haven't a lot of experience in template programming I don't know how I can complete the "pattern".
Code:
// test.cpp
#include <iostream>
#include <vector>
using namespace std;
struct Base
{
virtual ~Base() {}
virtual void visit() = 0;
};
template<typename Visitor>
struct ElementBase : public Base
{
// No virtual.
void visit()
{
_e.visit(this);
}
private:
Visitor _e;
};
// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor>
{
ElementA() : a(5) {}
int a;
};
// Visitors.
struct VisitorA
{
void visit(ElementBase<VisitorA> *a)
{
ElementA<VisitorA>* elto = dynamic_cast<ElementA<VisitorA>*>(a);
cout << elto->a << endl;
}
/*
void visit(ElementA<VisitorA> *a)
{
cout << a->a << endl;
}
*/
};
std::vector<Base*> v;
int main()
{
v.push_back(new ElementA<VisitorA>());
for (auto i : v)
i->visit();
}
This works fine and its output is 5 (as expected). But that I pretend is to make the same but directly with the second (commented) version of the "visit" in VisitorA.
Obviously, this doesn't work because "this" has the type ElementBase<...>*.
How can I downcast the pointer "this" to the actual derived class inside ElementBase?

Like user786653 says, the Curiously Recurring Template Pattern can solve this
template<typename Visitor, typename Derived>
struct ElementBase : public Base
{
void visit()
{
_e.visit(static_cast<Derived*>(this));
}
private:
Visitor _e;
};
// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor, ElementA<Visitor> >
{
ElementA() : a(5) {}
int a;
};
// Visitors.
struct VisitorA
{
void visit(ElementA<VisitorA> *a)
{
cout << a->a << endl;
}
};

Related

using intermediate class in a Crtp hierarchy without declaring a new class

I have a hierarchy similar to the following:
#include <iostream>
template<typename DerivedCrtp>
struct A
{
void Print() { std::cout << "A";}
};
struct B : public A<B>
{
};
template<typename DerivedCrtp>
struct C : public A<C<DerivedCrtp>>
{
void Print() { std::cout << "C";}
};
template<typename DerivedCrtp>
struct D : public C<D<DerivedCrtp>>
{
void Print() { std::cout << "D";}
};
struct CFinalized : public C<CFinalized>
{
void Print() { std::cout << "CFinal";}
};
template<typename DerivedCrtp = CSmart<>>
struct CSmart : public A<C<DerivedCrtp>>
{
void Print() { std::cout << "C";}
};
int main()
{
C<int> c;
D<int> d;
CFinalized cf;
c.Print();
d.Print();
cf.Print();
}
Because C is using crtp I can't directly use it without providing the self derived type DerivedCrtp.
In order to use it I need to "finalize" it's type (see CFinalized).
It works but every time I need to use a class part of that hierarchy (that in my real code is deeper and contains several more template parameters), I need to explicitly declare a new class.
Is there a smarter way to do this?

C++ vector of custom template class as member

I'm currently coding a program in c++ using a template class:
template<typename TYPE>
class TemplateClass {
private:
TYPE t;
};
I have another class which acts as manager of my TemplateClass which should store multiple instances of this class in a vector. Different instances should have different types e.g. int, std::string, etc.. Speaking in Java ways the solution would be to just use something like in the example below but it seems like this is not possible in C++.
class ManagerClass {
private:
// Here seems to be the problem.
std::vector<TemplateClass<?>> templates;
}
Is it possible to do something like that?
Thank you for all answers
If you know all the types that will be stored in the std::vector at compile time I'd use an std::variant in such a case.
// This is used for the visitor pattern.
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
// The below line not needed in C++20...
template<class... Ts> overload(Ts...) -> overload<Ts...>;
template<typename T>
struct MyClass { T value; };
using types = std::variant<
MyClass<std::string>,
MyClass<int>,
MyClass<double>>;
int main()
{
std::vector<types> stuff{};
stuff.push_back(MyClass<std::string>{});
stuff.push_back(MyClass<int>{});
stuff.push_back(MyClass<double>{});
for(const auto& v : stuff)
{
if (std::holds_alternative<MyClass<std::string>>(v))
{
std::cout << "Im a string\n";
}
else if (auto* p{std::get_if<MyClass<int>>(&v)})
{
std::cout << "Im an int\n";
}
else
{
auto t = std::get<MyClass<double>>(v);
std::cout << "Im a double\n";
}
// Or you can use the visitor pattern.
std::visit(overload{
[](const MyClass<std::string>& ) { std::cout << "I'm a string\n"; },
[](const MyClass<int>& ) { std::cout << "I'm a int\n"; },
[](const MyClass<double>& ) { std::cout << "I'm a double\n"; },
}, v);
}
}
If you can use C++17, you can use std::any or std::variant.
class ManagerClass {
private:
using variant_type = std::variant<
TemplateClass<std::string>,
TemplateClass<int>,
TemplateClass<double> >;
std::vector<variant_type> templates;
};
This is one way of doing it via runtime polymorphishm, which is achieved by function overriding. Function overriding occurs when a derived class has a definition for one of the member functions of the base class. That base function is said to be overridden.
#include <iostream>
#include <vector>
using namespace std;
// Base class declaration
class Base {
public:
virtual void print()
{
cout << "Base" << endl;
}
virtual ~Base(){}
};
// Derived Class 1
class Derived1 : public Base {
public:
void print()
{
cout << "Derived1" << endl;
}
};
// Derived class 2
class Derived2 : public Base {
public:
void print()
{
cout << "Derived2" << endl;
}
};
int main()
{
Base* d1 = new Derived1();
Base* d2 = new Derived2();
vector<Base*> myVec;
myVec.push_back(d1);
myVec.push_back(d2);
for (auto i : myVec) {
i->print();
}
delete d1;
delete d2;
return 0;
}

multiple static interfaces with implementation-dependent type of member function

I have two interfaces that I want to use with CRTP for static polymorphism. One of them contains a function whose types in the signature are implementation-dependent.
This problem looks like what has been asked here without solution. The solution I came up with includes an additional templated structure defining the type. This template is then specialized for the implementation avoiding the "invalid use of incomplete type" error.
Here my code
#include <iostream>
#include <memory>
template<class impl1>
struct Interface1 {
double foo() { return static_cast<impl1*>(this)->fooimpl();}
};
template<class impl1, class impl2>
struct typeHelp;
template<class impl1, class impl2>
struct Interface2 {
void bar(typename typeHelp<impl1,impl2>::type value) {
static_cast<impl2*>(this)->barimpl(value);
}
};
//Implementation2 pre declaration
template<class impl1>
struct Implementation2;
//Partial specialization of templated typeHelp
template<class impl1>
struct typeHelp<impl1, Implementation2<impl1>> {
using type = int;
};
//Implementation2
template<class impl1>
struct Implementation2 : public Interface2<impl1, Implementation2<impl1>> {
std::shared_ptr<Interface1<impl1>> imp1;
void barimpl(typename typeHelp<impl1,Implementation2>::type value) {
std::cout << imp1->foo() << " " << value << std::endl;
}
};
//Implementation1
struct Implementation1 : public Interface1<Implementation1> {
double fooimpl() {return 0.;}
};
int main()
{
Implementation2<Implementation1> obj;
obj.imp1 = std::make_shared<Implementation1>();
obj.bar(4);
}
What I don't like in this code is that Interface2 and typeHelp depend on template parameter impl1. This works for my particular case, where Implementation2 is templated with respect to impl1 but it wouldn't if Implementation2 weren't. I wonder if there is a more general and elegant solution to this problem.
My bad; a little bit more of search and I would have found the answer. On this link, Andy G points out that it is possible to specialize a class template with a templated class. The result is more clean than before
#include <iostream>
#include <memory>
//Interface1.hpp
template<class impl1>
struct Interface1 {
double foo() { return static_cast<impl1*>(this)->fooimpl();}
};
//Interface2.hpp
template<class impl2>
struct typeHelp;
template<class impl2>
struct Interface2 {
void bar(typename typeHelp<impl2>::type value) {
static_cast<impl2*>(this)->barimpl(value);
}
};
//Implementation2.hpp
template<class impl1>
struct Implementation2;
//specialization of typeHelp with templated class
template<class impl1>
struct typeHelp<Implementation2<impl1>> {
using type = int;
};
//Actual implementation of Implementation2
template<class impl1>
struct Implementation2 : public Interface2<Implementation2<impl1>> {
std::shared_ptr<Interface1<impl1>> imp1;
void barimpl(typename typeHelp<Implementation2<impl1>>::type value) {
std::cout << imp1->foo() << " " << value << std::endl;
}
};
//Implementation1.hpp
struct Implementation1 : public Interface1<Implementation1> {
double fooimpl() {return 0.;}
};
//Main.hpp
int main()
{
Implementation2<Implementation1> obj;
obj.imp1 = std::make_shared<Implementation1>();
obj.bar(4);
}

Iterate over different CRTP Derived class methods

In an example below I have a pretty typical CRTP example, two different derived classes that both have a method bar. The base class has a method foo which just forwards to some derived bar method
#include <iostream>
template<typename Derived>
class Base {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
class DerivedA : public Base<DerivedA> {
public:
void bar() {
::std::cout << "A\n";
}
};
class DerivedB : public Base<DerivedB> {
public:
void bar() {
::std::cout << "B\n";
}
};
int main() {
DerivedA a;
DerivedB b;
a.foo();
b.foo();
}
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
You can use Boost.Variant. For example:
typedef boost::variant<DerivedA, DerivedB> Derived;
struct BarCaller : public boost::static_visitor<void> {
template <class T>
void operator()(T& obj) {
obj.bar();
}
};
int main() {
std::vector<Derived> vec{DerivedA(), DerivedB(), DerivedA()};
BarCaller bar;
for (Derived& obj : vec) {
obj.apply_visitor(bar);
}
}
This lets you store heterogeneous types in a vector or other STL container (by using a "discriminated union"), and lets you call a specific function on all of them regardless of their not having a common ancestor or any virtual methods.
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different.
You can have a base class of Base<T> for all T, then, you can have a list/vector/array of pointers to the base class, if that works for you.
struct BaseOne
{
virtual void foo() = 0;
virtual ~BaseOne() {}
};
template<typename Derived>
class Base : struct BaseOne {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
and then,
int main() {
std::vector<BaseOne*> v {new DerivedA, new DerivedB };
for ( auto item : v )
item->bar();
for ( auto item : v )
delete item;
}
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
No, there isn't.
As per now, variant has became part of the C++17 standard and the solution to the problem can be solved by std::variant and std::visit as follows.
The template class in the example is Interface<> and use the CRTP idiom to force derived class to implement helloImpl():
#include <iostream>
#include <vector>
#include <variant>
template<typename Implementer>
struct Interface {
void hello() const {
static_cast<Implementer const *>(this)->helloImpl();
}
};
A couple of class examples with different implementations of helloImpl()
struct Hello1 : public Interface<Hello1> {
void helloImpl() const {
std::cout << "Hello1" << std::endl;
}
};
struct Hello2 : public Interface<Hello2> {
void helloImpl() const {
std::cout << "Hello2" << std::endl;
}
};
And here is how to use it to store data in a vector<> container and its traversal:
int main() {
using var_t = std::variant<Hello1, Hello2>;
std::vector<var_t> items{Hello1(), Hello1(), Hello2()};
for(auto &item: items) {
std::visit([](auto &&arg) {
arg.hello();
}, item);
}
return 0;
}

Using the Visitor Pattern with template derived classes

I try to implement the Visitor pattern with templated derived classes
I work with gcc 4.5
here is the VisitorTemplate.hpp, I specialized Derived in the class Visitor, but I'd like to be able to handle any type:
edit : thanks to the suggestions of interjay, the code compiles and runs without errors now
#ifndef VISITORTEMPLATE_HPP_
#define VISITORTEMPLATE_HPP_
#include <iostream>
#include <string>
using namespace std;
template<class T> Derived;
class Visitor
{
public:
virtual void visit(Derived<string> *e) = 0;
};
class Base
{
public:
virtual void accept(class Visitor *v) = 0;
};
template<class T>
Derived: public Base
{
public:
virtual void accept(Visitor *v)
{
v->visit(this);
}
string display(T arg)
{
string s = "This is : " + to_string(arg);
return s;
}
};
class UpVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Up on " + e->display("test") << '\n';
}
};
class DownVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Down on " + e->display("test") << '\n';
}
};
#endif /* VISITORTEMPLATE_HPP_ */
main.cpp
Base* base = new Derived<string>();
Visitor* up = new UpVisitor();
Visitor* down = new DownVisitor();
base->accept(up);
base->accept(down);
Now my goal is to use Derived in visit without specializing; unfortunately, visit is a virtual method so I can't template it
From Modern C++ - Design Generic Programming and Design Patterns Applied - Andrei Alexandrescu
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T, typename R = int>
class Visitor
{
public:
virtual R visit(T &) = 0;
};
template <typename R = int>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {};
virtual ReturnType accept(BaseVisitor & )
{
return ReturnType(0);
}
protected:
template <class T>
static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor)
{
if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor))
{
return p->visit(visited);
}
return ReturnType(-1);
}
#define VISITABLE() \
virtual ReturnType accept(BaseVisitor &v) \
{ return acceptVisitor(*this, v); }
};
/** example of use */
class Visitable1 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class Visitable2 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1, int>,
public Visitor<Visitable2, int>
{
public:
int visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept(visitor);
visitable2.accept(visitor);
}
Is possible to avoid dynamic_cast with CRTP pattern like:
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T>
class Visitor
{
public:
virtual void visit(T &) = 0;
};
template <class Visitable>
class BaseVisitable
{
public:
template <typename T>
void accept(T & visitor)
{
visitor.visit(static_cast<Visitable &>(*this));
}
};
/** example of use */
class Visitable1 : public BaseVisitable<Visitable1>
{
};
class Visitable2 : public BaseVisitable<Visitable2>
{
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1>,
public Visitor<Visitable2>
{
public:
void visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept<VisitorDerived>(visitor);
visitable2.accept<VisitorDerived>(visitor);
}
Your Derived class cannot use Visitor because it hasn't been defined yet (it was only forward declared, and is therefore an incomplete type).
You can fix the compile error by putting the Visitor definition before Derived. You will also need to forward-declare Derived before defining Visitor:
template <class T> class Derived;
class Visitor {
public:
virtual void visit(Derived<string> *e) = 0;
};
template <class T>
class Derived : public Base {
//.... can call Visitor methods here ...
};