| Home | Libraries | People | FAQ | More

##### Fuzzy and Exact Matches of Terminals

The terminals in an expression tree could be const or non-const references, or they might not be references at all. When writing grammars, you usually don't have to worry about it because `proto::matches<>` gives you a little wiggle room when matching terminals. A grammar such as `proto::terminal<int>` will match a terminal of type `int`, `int &`, or `int const &`.

You can explicitly specify that you want to match a reference type. If you do, the type must match exactly. For instance, a grammar such as `proto::terminal<int &>` will only match an `int &`. It will not match an `int` or an `int const &`.

The table below shows how Proto matches terminals. The simple rule is: if you want to match only reference types, you must specify the reference in your grammar. Otherwise, leave it off and Proto will ignore const and references.

Table 1.7. proto::matches<> and Reference / CV-Qualification of Terminals

Terminal | Grammar | Matches?
--- | --- | ---
T | T | yes
T & | T | yes
T const & | T | yes
T | T & | no
T & | T & | yes
T const & | T & | no
T | T const & | no
T & | T const & | no
T const & | T const & | yes

This begs the question: What if you want to match an `int`, but not an `int &` or an `int const &`? For forcing exact matches, Proto provides the `proto::exact<>` template. For instance, `proto::terminal< proto::exact<int> >` would only match an `int` held by value.

Proto gives you extra wiggle room when matching array types. Array types match themselves or the pointer types they decay to. This is especially useful with character arrays. The type returned by `proto::as_expr("hello")` is `proto::terminal<char const[6]>::type`. That's a terminal containing a 6-element character array. Naturally, you can match this terminal with the grammar `proto::terminal<char const[6]>`, but the grammar `proto::terminal<char const *>` will match it as well, as the following code fragment illustrates.

    struct CharString
      : proto::terminal< char const * >
    {};

    typedef proto::terminal< char const[6] >::type char_array;

    BOOST_MPL_ASSERT(( proto::matches< char_array, CharString > ));

What if we only wanted `CharString` to match terminals of exactly the type `char const *`? You can use `proto::exact<>` here to turn off the fuzzy matching of terminals, as follows:

    struct CharString
      : proto::terminal< proto::exact< char const * > >
    {};

    typedef proto::terminal<char const[6]>::type char_array;
    typedef proto::terminal<char const *>::type  char_string;

    BOOST_MPL_ASSERT(( proto::matches< char_string, CharString > ));
    BOOST_MPL_ASSERT_NOT(( proto::matches< char_array, CharString > ));

Now, `CharString` does not match array types, only character string pointers.

The inverse problem is a little trickier: what if you wanted to match all character arrays, but not character pointers? As mentioned above, the expression `as_expr("hello")` has the type `proto::terminal< char const[ 6 ] >::type`. If you wanted to match character arrays of arbitrary size, you could use `proto::N`, which is an array-size wildcard. The following grammar would match any string literal: `proto::terminal< char const[ proto::N ] >`.

Sometimes you need even more wiggle room when matching terminals. For example, maybe you're building a calculator EDSL and you want to allow any terminals that are convertible to `double`. For that, Proto provides the `proto::convertible_to<>` template. You can use it as: `proto::terminal< proto::convertible_to< double > >`.

There is one more way you can perform a fuzzy match on terminals. Consider the problem of trying to match a `std::complex<>` terminal. You can easily match a `std::complex<float>` or a `std::complex<double>`, but how would you match any instantiation of `std::complex<>`? You can use `proto::_` here to solve this problem. Here is the grammar to match any `std::complex<>` instantiation:

    struct StdComplex
      : proto::terminal< std::complex< proto::_ > >
    {};

When given a grammar like this, Proto will deconstruct the grammar and the terminal it is being matched against and see if it can match all the constituents.