2013-05-13 1 views
9

Я застреваю с проблемой дублирования кода, касающейся шаблона посетителя для дерева. Текущая ситуация следующая: у меня есть дерево, состоящее из двух разных классов узлов, т. Е. Листьев и нелистовых. Кроме того, у меня есть два базовых класса посетителя, которые выглядят очень похожими, за исключением того, что один посещает деревья-деревья и другие неконсольные деревья. Фактические действия, которые должны делать конкретные посетители, не зависят от конкретных типов узлов. Я дам краткий пример:Шаблон посетителя для const и nonconst версий дерева

class Visitor; 
class ConstVisitor; 

class Node { 
public: 
    virtual void accept(Visitor&) = 0; 
    virtual void accept(ConstVisitor&) const = 0; 
}; 

class Leaf : public Node { 
    virtual void accept(Visitor& v)  {v.visitLeaf(*this);} 
    virtual void accept(ConstVisitor& cv) {cv.visitLeaf(*this);} 
}; 

class CompoundNode : public Node { 
public: 
    vector<Node*> getChildren() const; 
    virtual void accept(Visitor& v)  {v.visitCompoundNode(*this);} 
    virtual void accept(ConstVisitor& cv) {cv.visitCompoundNode(*this);} 
}; 

class Visitor { 
protected: 
    virtual void processNode(Node& node) = 0; 
public: 
    void visitLeaf(Leaf& leaf) { 
    processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNode& cNode) { 
    processNode(cNode); 
    auto children = cNode.getChildren(); 
    for (auto child : children) 
     child->accept(this); 
    } 
}; 

class ConstVisitor { 
protected: 
    virtual void processNode(Node const& node) = 0; 
public: 
    void visitLeaf(Leaf const& leaf) { 
    processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNode const& cNode) { 
    processNode(cNode); 
    auto children = cNode.getChildren(); 
    for (auto child : children) 
     child->accept(this); 
    } 
}; 

Конкретные классы наследуют посетителя либо из Visitor или ConstVisitor, в зависимости от того, имеет ли их метод processNode изменять узлы посетили или нет.

Понимаете, существует много дублирования кода между двумя посетителями, и поскольку мне придется реализовать другую стратегию обхода, также как для узлов const, так и для nonconst, я хочу избежать дублирования. Есть ли возможность извлечь дубликат кода, желательно без использования const_cast повсюду?

ответ

11

Вы можете определить шаблон TVisitor класса, как это сделано ниже:

#include <type_traits> 

class Node; 
class CompoundNode; 
class Leaf; 

template<bool isNonConstVisitor> 
class TVisitor 
{ 
    typedef typename std::conditional<isNonConstVisitor, 
     Node, Node const>::type node_type; 

    typedef typename std::conditional<isNonConstVisitor, 
     CompoundNode, CompoundNode const>::type compound_node_type; 

    typedef typename std::conditional<isNonConstVisitor, 
     Leaf, Leaf const>::type leaf_node_type; 

protected: 

    virtual void processNode(node_type& node) = 0; 

public: 

    void visitLeaf(leaf_node_type& leaf) { processNode(leaf); } 

    void visitCompoundNode(compound_node_type& cNode) { 
     processNode(cNode); 
     auto children = cNode.getChildren(); 
     for (auto child : children) { child->accept(*this); } 
    } 
}; 

И затем использовать Visitor и ConstVisitor как псевдонимы типа для соответствующих инстанциацию этого шаблона класса:

typedef TVisitor<true> Visitor; 
typedef TVisitor<false> ConstVisitor; 
+0

Спасибо, это был быстрый и чистый раствор. Я надеюсь, что мои коллеги не слишком сильно ненавижу шаблоны ;-) –

+0

@ArneMertz: Хорошо, удачи в вашем проекте;) –

0

Вы можете использовать шаблоны :

template<typename NodeType, 
     typename CompoundNodeType, 
     typename LeafType> 
class BaseVisitor { 
protected: 
    virtual void processNode(NodeType& node) = 0; 
public: 
    void visitLeaf(LeafType& leaf) { 
     processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNodeType& cNode) { 
     processNode(cNode); 
     auto children = cNode.getChildren(); 
     for (auto child : children) 
     child->accept(this); 
    } 
}; 

class Visitor: public BaseVisitor<Node, CompoundNode, Leaf> { 
}; 

class ConstVisitor: public BaseVisitor<const Node, const CompoundNode, const Leaf> { 
};