这是一个boost::variant
基于节点系统的快速草图:
class Node;
struct Empty {};
// Keep enum and variant in sync:
enum NodeType {
eEmptyNode,
eStringNode,
eIntNode,
eListNode,
};
typedef std::vector< const Node > NodeList;
typedef boost::variant< std::string, int, NodeList > NodeData;
// Keep this in sync with types in Node and enum:
NodeType GetNodeType( Empty const& ) { return eEmptyNode; }
NodeType GetNodeType( std::string const& ) { return eStringNode; }
NodeType GetNodeType( int const& ) { return eIntNode; }
NodeType GetNodeType( NodeList const& ) { return eListNode; }
// Some helper code:
struct GetNodeType_visitor
{
typedef NodeType return_type;
template<typename T>
NodeType operator()( T const& t ) const { return GetNodeType(t); }
};
template<typename T, typename Function>
struct OneType_visitor
{
typedef bool return_type;
Function func;
OneType_visitor( Function const& f ):func(f) {}
template<typename U>
bool operator()( U const& u ) const { return false; }
bool operator()( T const& t ) const { func(t); return true; }
};
struct Node
{
NodeData data;
NodeType GetType() { return boost::apply_visitor( GetNodeType_visitor, data ); }
template<typename T, typename Function>
bool Apply( Function const& func ) const
{
return boost::apply_visitor( OneType_visitor<T>(func), data );
}
template<typename T>
Node( T const& t ):data(t) {}
Node():data(Empty()) {}
};
// example usage:
int main()
{
NodeList nodes;
nodes.push_back( Node<int>( 7 ) );
nodes.push_back( Node<std::string>( "hello" ) );
Node root( nodes );
Assert( root.GetType() == eListNode );
std::function<void(Node const&)> PrintNode;
auto PrintInt = [](int const& i) { std::cout << "#" << i; };
auto PrintString = [](std::string const& s) { std::cout << "\"" << s << "\""; };
auto PrintList = [&](NodeList const& list) {
std::cout << "[";
for (auto it = list.begin(); it !=list.end(); ++it)
{
if (it != list.begin()) std::cout << ",";
PrintNode( *it );
}
std::cout << "]";
}
auto PrintEmpty = [](Empty const&) { std::cout << "{}"; }
PrintNode = [&](Node const& n)
{
bool bPrinted = false;
bPrinted = n.Apply<int>( PrintInt ) || bPrinted;
bPrinted = n.Apply<std::string>( PrintString ) || bPrinted;
bPrinted = n.Apply<NodeList>( PrintList ) || bPrinted;
bPrinted = n.Apply<Empty>( PrintEmpty ) || bPrinted;
Assert(bPrinted);
}
PrintNode(root);
}
代码未经测试,但基本思想应该成立。
请注意,我使用的是不可变节点,因为这是用于类似 lisp 的语言。真的我应该使用std::shared_ptr<const Node>
或类似的东西,所以两棵树可以共享数据。
boost::variant
处理动态类型问题。