11

ツリーのビジター パターンに関して、コードの重複の問題に悩まされています。現在の状況は次のとおりです。2 つの異なるノード クラス、つまりリーフと非リーフで構成されるツリーがあります。さらに、1 つが const ツリーを訪問し、もう 1 つが非 const ツリーを訪問することを除いて、非常によく似た 2 つのビジター ベース クラスがあります。具体的な訪問者が実行する必要がある実際のアクションは、ノードの具体的なタイプとは無関係です。簡単な例を挙げます。

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

具体的なビジター クラスは、そのメソッドが訪問したノードを変更する必要があるかどうかに応じて、 fromVisitorまたは fromのいずれかを継承します。ConstVisitorprocessNode

ご覧のとおり、2 つのビジター間で多くのコードの重複があり、const ノードと非 const ノードの両方に対して別のトラバーサル戦略を実装する必要があるため、その重複を避けたいと考えています。const_castできればすべての場所を使用せずに、重複したコードを抽出する可能性はありますか?

4

2 に答える 2

12

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

そして、そのクラス テンプレートの対応するインスタンス化の型エイリアスとしてVisitorandを使用します。ConstVisitor

typedef TVisitor<true> Visitor;
typedef TVisitor<false> ConstVisitor;
于 2013-05-13T13:26:09.143 に答える
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> {
};
于 2013-05-13T13:34:24.510 に答える