Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Adapting Existing Types to Proto

The preceding discussions of defining Proto front ends have all made a big assumption: that you have the luxury of defining everything from scratch. What happens if you have existing types, say a matrix type and a vector type, that you would like to treat as if they were Proto terminals? Proto usually trades only in its own expression types, but with BOOST_PROTO_DEFINE_OPERATORS(), it can accomodate your custom terminal types, too.

Let's say, for instance, that you have the following types and that you can't modify then to make them native Proto terminal types.

namespace math
{
    // A matrix type ...
    struct matrix { /*...*/ };

    // A vector type ...
    struct vector { /*...*/ };
}

You can non-intrusively make objects of these types Proto terminals by defining the proper operator overloads using BOOST_PROTO_DEFINE_OPERATORS(). The basic procedure is as follows:

  1. Define a trait that returns true for your types and false for all others.
  2. Reopen the namespace of your types and use BOOST_PROTO_DEFINE_OPERATORS() to define a set of operator overloads, passing the name of the trait as the first macro parameter, and the name of a Proto domain (e.g., proto::default_domain) as the second.

The following code demonstrates how it works.

namespace math
{
    template<typename T>
    struct is_terminal
      : mpl::false_
    {};

    // OK, "matrix" is a custom terminal type
    template<>
    struct is_terminal<matrix>
      : mpl::true_
    {};

    // OK, "vector" is a custom terminal type
    template<>
    struct is_terminal<vector>
      : mpl::true_
    {};

    // Define all the operator overloads to construct Proto
    // expression templates, treating "matrix" and "vector"
    // objects as if they were Proto terminals.
    BOOST_PROTO_DEFINE_OPERATORS(is_terminal, proto::default_domain)
}

The invocation of the BOOST_PROTO_DEFINE_OPERATORS() macro defines a complete set of operator overloads that treat matrix and vector objects as if they were Proto terminals. And since the operators are defined in the same namespace as the matrix and vector types, the operators will be found by argument-dependent lookup. With the code above, we can now construct expression templates with matrices and vectors, as shown below.

math::matrix m1;
math::vector v1;
proto::literal<int> i(0);

m1 * 1;  // custom terminal and literals are OK
m1 * i;  // custom terminal and Proto expressions are OK
m1 * v1; // two custom terminals are OK, too.

PrevUpHomeNext