Boost logo

Boost :

From: Zach Laine (whatwasthataddress_at_[hidden])
Date: 2024-02-26 07:36:00

On Thu, Feb 22, 2024 at 2:17 AM Zach Laine <whatwasthataddress_at_[hidden]> wrote:
> On Wed, Feb 21, 2024 at 12:27 PM Phil Endecott via Boost
> <boost_at_[hidden]> wrote:
> >


> > One other advantage of having the lambda return a result could
> > be improving how the semantic type (aka attribute type) of a
> > rule is set. For example, if I have the rule
> >
> > degrees >> minutes
> >
> > where degrees and minutes return doubles, the semantic type of
> > the combined rule is something like tuple<double,double>. But
> > I'm going to add a semantic action that adds the two values as
> > shown above, returning one double. If the return value of the
> > semantic action's lambda were used as the semantic type of the
> > rule then we could write:
> >
> > auto rule = (degrees >> minutes)
> > [( [](auto d, auto m) { return d + m/60.0; } )];
> >
> > and rule would return a double to its parent rule. As it is, the
> > semantic action doesn't change the type and we have to
> > explicitly and verbosely declare the rule as returning a double.
> I had not thought of this before, but I really like it. I'll have to
> think pretty deeply about whether there is some reason this might not
> work, but I'm definitely going to try to implement this. I'm thinking
> that the rule would be: if std::apply(f, tup) is well-formed (where f
> is your invocable, and tup is your tuple of values returned by
> _attr()), and decltype(std::apply(f, tup)) is assignable to _val(),
> then do the semantic action as _val(ctx) = std::apply(f, _attr(ctx));
> otherwise, the semantic action gets called with the current context..
> There would be a special case when _attr() is not a tuple, but you get
> the idea. Ticket to track it:

This is now implemented. The logic I came up with is this. In
general, the return value of the semantic action can be used to assign
the value that would normally be assigned to _val(ctx) in a semantic
action, but after the semantic action is executed. So, now you can
write a semantic action with a signature like void(auto&ctx) like
before, or you can write one like T(auto&ctx), for some non-void type
T. In the latter case, the returned T gets assigned to _val(ctx).
You can also write a semantic action that takes the attribute and
returns something assignable to _val(ctx), or even one that takes the
individual elements of the attribute, if it is a tuple, and returns
something assignable to _val(ctx).

>From the updated docs:

More formally, within a rule, the use of a semantic action is
determined as follows. Assume we have a function APPLY that calls a
function with the elements of a tuple, like std::apply. For some
context ctx, semantic action action, and attribute attr, action is
used like this:

- _val(ctx) = action(std::move(attr)), if that is well-formed;

- otherwise, _val(ctx) = APPLY(action, std::move(attr)), if that is well-formed;

- otherwise, _val(ctx) = action(ctx), if that is well-formed;

- otherwise, action(ctx).

The first two cases do not pass the context to the action at all. The
last case is the normal use of semantic actions outside of rules.


Boost list run by bdawes at, gregod at, cpdaniel at, john at