Boost logo

Proto :

Subject: [proto] [proto-11] expression extension
From: Eric Niebler (eric_at_[hidden])
Date: 2012-06-03 03:41:03


Hey all, this is just an FYI. I've been hard at work at a ground-up
redesign of proto for C++11. I've gotten far enough along that I know
what expression extension will look like, so I thought I'd share. This
should interest those who want finer control over how expressions in
their domain are constructed. Without further ado:

    template<typename Tag, typename Args>
    struct MyExpr;

    struct MyDomain
      : proto::domain<MyDomain>
    {
        struct make_expr
          : proto::make_custom_expr<MyExpr, MyDomain>
        {};
    };

    template<typename Tag, typename Args>
    struct MyExpr
      : proto::basic_expr<Tag, Args, MyDomain>
      , proto::expr_assign<MyExpr<Tag, Args>, MyDomain>
      , proto::expr_subscript<MyExpr<Tag, Args>, MyDomain>
      , proto::expr_function<MyExpr<Tag, Args>, MyDomain>
    {
        BOOST_PROTO_REGULAR_TRIVIAL_CLASS(MyExpr);
        using proto::basic_expr<Tag, Args, MyDomain>::basic_expr;
        using proto::expr_assign<MyExpr, MyDomain>::operator=;
    };

Things to note:

1) Rather than writing expression wrappers, you'll be writing actual
expression types. Proto provides helpers that make this easy. To get the
basics, inherit from basic_expr. To get tree-building assign, subscript,
and function call operators, inherit from expr_assign, expr_subscript
and expr_function respectively.

2) Rather than writing generators, you'll be defining per-domain
make_expr function objects that accept a tag and a number of children.
How you decide to assemble these into an expression is up to you, but
you can use a helper like make_custom_expr above to simplify things.

3) There are other per-domain customization points: (a) store_value,
which specifies the capture policy for non-proto objects in expressions,
and (b) store_child, which specifies how children are stored. For both
(a) and (b), the default is: lvalues are stored by reference and rvalues
are stored by (moved from) value. Expressions can safely be stored in
auto variables by default.

4) Expressions are both Regular and Trivial. Regular means they have
normal copy and assign semantics (movable, too). Trivial means they can
be statically initialized. All their constructors are constexpr. Yes,
expressions can have both regular assignment semantics *and*
tree-building assignment operators. "x=y" is normal assignment when x
and y have the same type. It builds a tree node when they don't. Also,
you'll have to opt in to get the address-of operator.

Caveat: there is no compiler that can handle the above yet. Clang is
close, but it doesn't support inheriting constructors. Instead of this:

        using proto::basic_expr<Tag, Args, MyDomain>::basic_expr;

you must do this:

        typedef proto::basic_expr<Tag, Args, MyDomain> proto_basic_expr;
        BOOST_PROTO_INHERIT_EXPR_CTORS(MyExpr, proto_basic_expr);

It's just a temporary hack.

Thanks all for now. Feedback welcome. If you have wishlist features for
proto-11, speak now.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Proto list run by eric at boostpro.com