非循环访客模式。将接受功能移动到一个地方

时间:2015-01-20 16:59:44

标签: c++ design-patterns visitor

下面我从accept (const ChooseVisitor&);中取出了Object函数并将其放在Menu<T>::Option中,以便只需要在那里调用它而不是那些将要调用的函数拥有accept功能。唯一的问题是T可能是一个指针或一个引用,或者其他什么,我需要变成一个没有指针或引用或常量等的常规类型......以获得T::Visitor*编译。

#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 个答案:

答案 0 :(得分:1)

您错过了::type。它应该是std::remove_pointer<T>::type

更新:要获得普通类型,您可以嵌套std::remove_模板 - std::remove_cv<typename std::remove_pointer<typename std:: remove_reference<T>::type>::type>::type