Sophie

Sophie

distrib > Mandriva > 9.1 > ppc > by-pkgid > b9ba69a436161613d8fb030c8c726a8e > files > 371

spirit-1.5.1-2mdk.noarch.rpm


Hello Y'all,

Yesterday, I sent in phoenix code that implements true local
variables. With a slight twist, the code can be made to return values
as was suggested in the list. Like before, no changes to the original
framework is needed. This is yet another example demonstratintg
phoenix's extensibility.

First, sample code. Find the first element > 5, print each element as
we traverse the container c. Print the result if one is found
(sample8.cpp):

    iterator it = find_if(c.begin(), c.end(),
        context<bool>()
        [
            cout << arg1,
            result = arg1 > 5,
            if_(!result)
            [
                cout << val(", ")
            ]
            .else_
            [
                cout << val(" found result == ") << arg1
            ]
        ]
    );

Changes to yesterday's code:

1) locals is renamed as context
2) The first type in the context-type list is the return type.
   Examples:

    bool return type, no locals:

        context<bool>()

    bool return type, int local:

        context<bool, int>()

    std::string return type, char const* local
    initialized to "hello", int local:

        context<std::string, char const*, int>("hello")

    void return type, int local initialized to 3

        context<void>(3)

    int return type, int local initialized to 3,
    std::string local initialized to "hello":

        context<int>(3, std::string("hello"))

The return value "result" is actually just like another local
variable, reminiscent of pascal. It would have looked more C++ like,
syntax wise, to use return_(some_expression) but the semantics would
have been more complex because a return(x) should exit the pseudo-
function which is non-trivial to implement and to the best of my
knowledge requires a throw of an exception that will be caught by the
context object. This will have unwanted overhead and use of an
exception as program flow-control is a no-no.

*** contexts can be nested (of course). Especially useful in
conjunction with statements which return void by default, as someone
in the list (Stoll?) suggested. ***

So here are the changes to yesterday's code:

I ------------------------------

namespace locals {

    actor<local_var<0> > const result   = local_var<0>();
    actor<local_var<1> > const loc1     = local_var<1>();
    actor<local_var<2> > const loc2     = local_var<2>();
    actor<local_var<3> > const loc3     = local_var<3>();
    actor<local_var<4> > const loc4     = local_var<4>();
}

Yesterday's loc1..locN place-holders were in namespace phoenix. Now I
put them in namespace phoenix::locals to avoid polluting the
namespaces (short common names such as these are likely to clash). One
can write:

    phoenix::locals::loc1

or:

    using namespace phoenix;
    locals::loc1

or:

    using namespace phoenix;
    using namespace phoenix::locals;
    loc1

Take note that actor<local_var<0> > is now named result.

II ------------------------------

locals_composite is now remaned context_composite
locals_gen is now remaned context_gen
locals(...) gen functions is now context(...) gen functions

III ------------------------------

context_composite::result is now written as:

    template <typename TupleT>
    struct result { typedef typename tuple_element<0, LocsT>::type type; };

Yesterday, it was:

    template <typename TupleT>
    struct result { typedef typename actor_result<ActorT, TupleT>::type type; };

The result of the context_composite is now the element zero (0) of
the locals (LocsT) tuple.

IV ------------------------------

context_composite::eval is now written as:

    template <typename TupleT>
    typename tuple_element<0, LocsT>::type
    eval(TupleT const& args) const
    {
        local_tuple<TupleT, LocsT>  local_context(args, locals);
        actor.eval(local_context);
        return local_context.locs[tuple_index<0>()];
    }

Yesterday, it was:

    template <typename TupleT>
    typename actor_result<ActorT, TupleT>::type
    eval(TupleT const& args) const
    {
        return actor.eval(local_tuple<TupleT, LocsT>(args, locals));
    }

It's almost the same. The only difference is that the zeroth (0th)
local variable is returned back to the caller of eval.

V ------------------------------

context(...) gen functions (was locals(...)) accept one less
initializer argument. The zeroth local (the return val) is always
default constructed.

------------------------------

That's it. Have fun... Told 'ya phoenix is way cool! I wrote these
changes in less than 20 mins. Tell me if this is useful and I will
incorporate this in the framework. Suggestions welcome (as always).

Cheers,
--Joel