2015-01-20 3 views
0

Ниже я вынул функцию accept (const ChooseVisitor&); из Object и разместил ее в Menu<T>::Option вместо этого, так что ее нужно было бы назвать там вместо многих классов, которые будут иметь функцию accept. Единственная проблема заключается в том, что T может быть указателем или ссылкой или что-то еще, и мне нужно превратиться в обычный тип без указателя или ссылки или const и т. Д., Чтобы получить T::Visitor* для компиляции.Ациклический шаблон посетителя. Перемещение функции accept только на одно место

#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>(); 
} 

Я начинаю с

template <typename T> 
struct GetVisitor { 
    using type = std::is_pointer<T>::value ? typename std::remove_pointer<T>::type::Visitor : typename T::Visitor; 
}; 

, но он не работает прямо сейчас, а также он должен обрабатывать все возможные типы. Какой самый элегантный способ сделать это? Есть ли простая функция, которая уже делает это?

ответ

1

Вам не хватает ::type. Он должен быть std::remove_pointer<T>::type

Update: Чтобы получить простой тип можно вложить в std::remove_ шаблоны - std::remove_cv<typename std::remove_pointer<typename std:: remove_reference<T>::type>::type>::type

+0

я обнаружил, что из только сейчас, но мне еще нужно обобщить все другие возможные абсорбции. Я обновил свой вопрос. О, и я верю, что вы знаете, откуда мой вопрос идет от gmbeard (из моего последнего вопроса). Я по-прежнему придерживаюсь вашей идеи, но поскольку различные действия будут происходить в зависимости от того, где используется меню, мне нужно передать разные типы посетителей в функцию select(), чтобы предоставлять разные переопределения для одного и того же типа T для разных ситуации. – prestokeys

+0

Да, ваш другой вопрос определенно является проблемой. Вы вникаете в мутные воды статических гетерогенных контейнеров. Вариант варианта/посетителя кажется единственным способом. – gmbeard