How about some boost magic?
#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
// A recursive tree structure made of std::vector.
template< typename T, class Allocator = std::allocator<T> >
struct vector_tree :
std::vector<
boost::variant< T, boost::recursive_wrapper< vector_tree< T, Allocator > > >,
Allocator >
{
using base = std::vector<
boost::variant< T, boost::recursive_wrapper< vector_tree< T, Allocator > > >,
Allocator >;
// Forward all constructors of the base class.
using base::base;
};
This type allows for unlimited nesting and has a very clean initialization syntax.
Usage examples
using mytree = vector_tree<int>;
// Construct a nested vector_tree with initializer list.
mytree tree{
1,
2,
mytree{
mytree{ 3, 4, 5 },
6,
}
};
// Add more stuff.
tree.push_back( 42 );
tree.push_back( mytree{ 43, 44 } );
// Add something to a child vector_tree.
// NOTE: boost::get() will throw a boost::bad_get exception if requested type is invalid
boost::get<mytree>( tree[ 2 ] ).push_back( 99 );
// To avoid the boost::bad_get exception, we can check if the child actually is a vector_tree:
if( mytree* pchild = boost::get<mytree>( &tree[ 2 ] ) )
{
(*pchild)[ 1 ] = 88;
}
Live Demo on Coliru.
Explanations
The boost::recursive_wrapper
is required because boost::variant
normally requires a complete type, but at the point of declaration vector_tree
is still incomplete.
boost::recursive_wrapper
actually is nothing magic. It's just a wrapper around a pointer! As we know, a pointer can be declared for an incomplete type without issues. This wrapper class just hides the fact that a pointer is used by taking care of allocation, deallocation and providing value semantics. It has special support by boost::variant
that makes the wrapper completely transparent, so the variant can be used as if there is no wrapper class at all.
NOTE: Since C++17 there is std::variant
but AFAIK there isn't a boost::recursive_wrapper
equivalent for it that can handle nesting transparently.