For you, the following may be done:
struct ExprTreeNode { bool is_value; int i; char c; std::vector< ExprTreeNode > v; ExprTreeNode( int i_ ) : is_value( true ), i( i_ ) {} ExprTreeNode( char c_, std::initializer_list< ExprTreeNode > v_ ) : is_value( false ), c( c_ ), v( v_ ) {} }; ExprTreeNode tn { '+', { 1, 2, { '*', { 3, 4 } } } };
(in practice you can combine i and c )
Here is a living example .
Update: As pointed out in another Q / A, where I used a similar method, the above behavior is undefined, since I use std::vector<ExprTreeNode> as a member, and at this point, ExprTreeNode not a full type. The following needs to be fixed:
struct ExprTreeNode { int value_; char op_; std::shared_ptr< void > subnodes_; ExprTreeNode( int v ) : value_( v ) {} ExprTreeNode( char op, std::initializer_list< ExprTreeNode > subnodes ); void print() const; }; typedef std::vector< ExprTreeNode > Nodes; ExprTreeNode::ExprTreeNode( char op, std::initializer_list< ExprTreeNode > l ) : op_(op), subnodes_(std::make_shared<Nodes>(l)) {}
Here shared_ptr used as well as a flag for a sheet / non-sheeted sheet, and if you want to use it, you need to transfer it first:
void ExprTreeNode::print() const { if( !subnodes_ ) { std::cout << value_; } else { std::cout << op_ << " ( "; for( const auto& e : *std::static_pointer_cast<Nodes>(subnodes_) ) { e.print(); std::cout << " "; } std::cout << ")"; } }
Here's an updated live example .