| Home | Libraries | People | FAQ | More

#### Accessing Parts of an Expression

After assembling an expression into a tree, you'll naturally want to be able to do the reverse, and access a node's children. You may even want to be able to iterate over the children with algorithms from the Boost.Fusion library. This section shows how.

###### Getting Expression Tags and Arities

Every node in an expression tree has both a tag type that describes the node, and an arity corresponding to the number of child nodes it has. You can use the `proto::tag_of<>` and `proto::arity_of<>` metafunctions to fetch them. Consider the following:

    template<typename Expr>
    void check_plus_node(Expr const &)
    {
        // Assert that the tag type is proto::tag::plus
        BOOST_STATIC_ASSERT((
            boost::is_same<
                typename proto::tag_of<Expr>::type
              , proto::tag::plus
            >::value
        ));

        // Assert that the arity is 2
        BOOST_STATIC_ASSERT( proto::arity_of<Expr>::value == 2 );
    }

    // Create a binary plus node and use check_plus_node()
    // to verify its tag type and arity:
    check_plus_node( proto::lit(1) + 2 );

For a given type `Expr`, you could access the tag and arity directly as `Expr::proto_tag` and `Expr::proto_arity`, where `Expr::proto_arity` is an MPL Integral Constant.

###### Getting Terminal Values

There is no simpler expression than a terminal, and no more basic operation than extracting its value. As we've already seen, that is what `proto::value()` is for.

    proto::terminal< std::ostream & >::type cout_ = {std::cout};

    // Get the value of the cout_ terminal:
    std::ostream & sout = proto::value( cout_ );

    // Assert that we got back what we put in:
    assert( &sout == &std::cout );

To compute the return type of the `proto::value()` function, you can use `proto::result_of::value<>`. When the parameter to `proto::result_of::value<>` is a non-reference type, the result type of the metafunction is the type of the value as suitable for storage by value; that is, top-level reference and qualifiers are stripped from it. But when instantiated with a reference type, the result type has a reference added to it, yielding a type suitable for storage by reference. If you want to know the actual type of the terminal's value including whether it is stored by value or reference, you can use `fusion::result_of::value_at<Expr, 0>::type`.

The following table summarizes the above paragraph.

Table 1.4. Accessing Value Types

Metafunction Invocation | When the Value Type Is ... | The Result Is ...
--- | --- | ---

`proto::result_of::value<Expr>::type`

`T`

    typename boost::remove_const<
        typename boost::remove_reference<T>::type
    >::type [a]

`proto::result_of::value<Expr &>::type`

`T`

    typename boost::add_reference<T>::type

`proto::result_of::value<Expr const &>::type`

`T`

    typename boost::add_reference<
        typename boost::add_const<T>::type
    >::type

`fusion::result_of::value_at<Expr, 0>::type` | `T` | `T`
[a] If `T` is a reference-to-function type, then the result type is simply `T`.

###### Getting Child Expressions

Each non-terminal node in an expression tree corresponds to an operator in an expression, and the children correspond to the operands, or arguments of the operator. To access them, you can use the `proto::child_c()` function template, as demonstrated below:

    proto::terminal<int>::type i = {42};

    // Get the 0-th operand of an addition operation:
    proto::terminal<int>::type &ri = proto::child_c<0>( i + 2 );

    // Assert that we got back what we put in:
    assert( &i == &ri );

You can use the `proto::result_of::child_c<>` metafunction to get the type of the Nth child of an expression node. Usually you don't care to know whether a child is stored by value or by reference, so when you ask for the type of the Nth child of an expression `Expr` (where `Expr` is not a reference type), you get the child's type after references and cv-qualifiers have been stripped from it.

    template<typename Expr>
    void test_result_of_child_c(Expr const &expr)
    {
        typedef typename proto::result_of::child_c<Expr, 0>::type type;

        // Since Expr is not a reference type,
        // result_of::child_c<Expr, 0>::type is a
        // non-cv qualified, non-reference type:
        BOOST_MPL_ASSERT((
            boost::is_same< type, proto::terminal<int>::type >
        ));
    }

    // ...
    proto::terminal<int>::type i = {42};
    test_result_of_child_c( i + 2 );

However, if you ask for the type of the Nth child of `Expr &` or `Expr const &` (note the reference), the result type will be a reference, regardless of whether the child is actually stored by reference or not. If you need to know exactly how the child is stored in the node, whether by reference or by value, you can use `fusion::result_of::value_at<Expr, N>::type`. The following table summarizes the behavior of the `proto::result_of::child_c<>` metafunction.

Table 1.5. Accessing Child Types

Metafunction Invocation | When the Child Is ... | The Result Is ...
--- | --- | ---

`proto::result_of::child_c<Expr, N>::type`

`T`

    typename boost::remove_const<
        typename boost::remove_reference<T>::type
    >::type

`proto::result_of::child_c<Expr &, N>::type`

`T`

    typename boost::add_reference<T>::type

`proto::result_of::child_c<Expr const &, N>::type`

`T`

    typename boost::add_reference<
        typename boost::add_const<T>::type
    >::type

`fusion::result_of::value_at<Expr, N>::type` | `T` | `T`

###### Common Shortcuts

Most operators in C++ are unary or binary, so accessing the only operand, or the left and right operands, are very common operations. For this reason, Proto provides the `proto::child()`, `proto::left()`, and `proto::right()` functions. `proto::child()` and `proto::left()` are synonymous with `proto::child_c<0>()`, and `proto::right()` is synonymous with `proto::child_c<1>()`.

There are also `proto::result_of::child<>`, `proto::result_of::left<>`, and `proto::result_of::right<>` metafunctions that merely forward to their `proto::result_of::child_c<>` counterparts.