2013-05-13 8 views
9

ツリーの訪問者パターンに関して、コードの重複の問題が残っています。現在の状況は次のとおりです。私は、リーフとノンリーフの2つの異なるノードクラスからなるツリーを持っています。さらに、私は2つの訪問者基底クラスを持っていますが、それらは非常に似ていますが、constツリーと他の非constツリーを訪問する点が異なります。具体的な訪問者がしなければならない実際のアクションは、ノードの具体的なタイプとは独立しています。私は簡単な例をあげる:ツリーの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); 
    } 
}; 

コンクリートビジタークラスは、そのprocessNode方法が訪問したノードかどうかを変更することがあるかどうかに応じて、VisitorからかConstVisitorのいずれかから継承します。

あなたは、2人の訪問者の間でコードの重複がたくさんあることと、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); } 
    } 
}; 

そして、そのクラスのテンプレートのインスタンス化に対応するために型の別名としてVisitorConstVisitorを使用する:

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> { 
}; 
関連する問題