Below I've taken out the accept (const ChooseVisitor&);
function out of Object
and placed it in Menu<T>::Option
instead so that it would only need to be called there instead of the many classes that will have the accept
function. The only problem is that T
may be a pointer or a reference, or whatever, and I need to turn into into a regular type without pointer or reference or const, etc... to get T::Visitor*
to compile.
#include <iostream>
#include <type_traits>
struct ChooseVisitor {
virtual ~ChooseVisitor() = default;
};
struct Object {
struct Visitor {
virtual void visit (Object*) const = 0;
};
// void accept (const ChooseVisitor&); // I've decided to move this into Menu instead (to avoid the repetitions in other classes).
};
struct PurchaseObjectVisitor : public ChooseVisitor, public Object::Visitor {
virtual void visit (Object* object) const {
std::cout << object << " purchased.\n";
}
};
template <typename T>
struct Menu {
struct Option {
T item;
template <typename> void accept (const ChooseVisitor&);
};
Option* option; // Assume Menu<T> with only one option for simplicity here.
template <typename> void choose() const;
void insert (const T& t) {option = new Option{t};}
};
template <typename T>
template <typename Visitor>
void Menu<T>::Option::accept (const ChooseVisitor& visitor) {
// using Type = typename std::remove_pointer<T>::type; // How to cover all possible cases?
const typename Type::Visitor* v = dynamic_cast<const typename Type::Visitor*> (&visitor);
if (v) v->visit(item);
}
template <typename T>
template <typename Visitor>
void Menu<T>::choose() const {
const Visitor visitor;
option->template accept<Visitor>(visitor); // template disambiguator needed.
}
int main() {
Menu<Object*> menu;
menu.insert (new Object);
menu.choose<PurchaseObjectVisitor>();
}
I'm starting with
template <typename T>
struct GetVisitor {
using type = std::is_pointer<T>::value ? typename std::remove_pointer<T>::type::Visitor : typename T::Visitor;
};
but it is not working right now, and also it needs to handle ALL the possible types. What's the most elegant way to do this? Is there a simple function that does that already?
You're missing ::type
. It should be std::remove_pointer<T>::type
Update: To get plain type you can nest the std::remove_
templates - std::remove_cv<typename std::remove_pointer<typename std:: remove_reference<T>::type>::type>::type