I have data stored in a C++ tree structure which I read in from a file. The tree looks like that:
class BaseNode {
  std::vector<BaseNode*> children_;
  ...
};
class WhiteNode : public BaseNode { ... };
class BlackNode : public BaseNode { ... };
After the tree is built, I would like to convert it, e.g. to a string.
In order to keep the tree code separate from the conversion code, I would like to use templates, i.e. implementing something like that:
template <class T>
T WhiteNode::Convert() { ... };
However, since the tree nodes are stored as BaseNode*, I don't know how to access such a template member function. And since template member functions cannot be inherited, I don't think this will work.
I did come up with a working solution, though:
class BaseConversion {
public:
  virtual ~BaseConversion() {}
  virtual void * FromBlack() = 0;
  virtual void * FromWhite() = 0;
};
template <class T>
class Conversion : public BaseConversion {
public:
  void * FromBlack();
  void * FromWhite();
};
class BaseNode {
  std::vector<BaseNode*> children_;
  virtual void * Convert(BaseConversion * conversion) = 0;
public:
  virtual ~BaseNode() {}
  template <class T>
  T Convert() {
    return *static_cast<T*>(Convert(new Conversion<T>));
  }
};
class WhiteNode : public BaseNode {
  void * Convert(BaseConversion * conversion) {
    return conversion->FromWhite();
  }
};
class BlackNode : public BaseNode {
  void * Convert(BaseConversion * conversion) {
    return conversion->FromBlack();
  }
};
And the transformation logic can be entirely separate:
template <>
void * Conversion<std::string>::FromWhite() {
  return new std::string("converting WHITE node to std::string ...");
}
template <>
void * Conversion<std::string>::FromBlack() {
  return new std::string("converting BLACK node to std::string ...");
}
Testing the code:
BaseNode * node = new BlackNode;
std::cout << node->Convert<std::string>() << std::endl;
node = new WhiteNode;
std::cout << node->Convert<std::string>() << std::endl;
returns the expected result:
converting BLACK node to std::string ...
converting WHITE node to std::string ...
Although this solution works, I am sure it can be done much easier. Any other, simpler solution I came up with failed, e.g. due to type erasure.
I would appreciate any help on that. Thanks!
Something similar to your solution but without void*.
class NodeVisitor
{
   virtual void VisitBlack(BlackNode* node);
   virtual void VisitWhite(BlackNode* node);
};
class BaseNode {
  std::vector<BaseNode*> children_;
  ...
  virtual void visit(NodeVisitor* visitor) = 0;
};
class WhiteNode : public BaseNode {
  virtual void visit(NodeVisitor* visitor) { visitor->visitWhite(this); }
};
class BlackNode : public BaseNode {
  virtual void visit(NodeVisitor* visitor) { visitor->visitBlack(this); }
};
Then
std::string convert(BaseNode* node)
{
    class ConvertVisitor
         : public NodeVisitor
    {
        ConvertVisitor(std::string* res)
            : m_res(res)
        { }
        virtual void VisitBlack(BlackNode* node)
        {
            *m_res = // convert black node to string;
        }
        virtual void VisitWhite(BlackNode* node)
        {
            *m_res = // convert white node to string;
        }
        std::string* m_res;
    };
    std::string res;
    ConvertVisitor visitor(&res);
    node->visit(&visitor);
    return res;
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With