Boost logo

Boost Users :

Subject: Re: [Boost-users] [Proto] First steps
From: Eric Niebler (eric_at_[hidden])
Date: 2010-11-09 11:27:49


On 11/8/2010 3:36 PM, Luc Danton wrote:
> Hello everyone,
>
> I've been meaning to learn to use Boost.Proto for quite some time and
> I've finally started getting my hands dirty in code ever since that
> fantastic video from BoostCon 2010. After the usual exercises that are
> presented in it and the docs, I've set up my own goal of trying to write
> composable futures (something that I think quite a lot of people have
> been doing in their own time).

That's an ambitious project for your first outing! Proto has a futures
example that you may have seen (libs/proto/example/futures.cpp), but it
doesn't address your concerns below.

> You can see the code at http://pastebin.com/DW4LckMP and I'd welcome
> comments on what I've been doing wrong and how I could improve the
> design. I also welcome answers to my following questions:

I've come to really dislike Proto's contexts. I personally prefer
grammars+transforms.

> * regarding copying, the docs present the following example:
> auto sum = boost::proto::lit(1) + 2;
> here, since the 1 is held by a reference which will outlive (in the
> variable sum) the actual literal expression (in the call to proto::lit)
> we will have UB.

Correct. Expression templates and "auto/decltype" don't co-exist
happily. Much care needs to be taken if storing these things in local
variables is part of your usage requirements.

> To avoid this exact problem, and since Boost.Proto is not move aware and
> std::future is move-only, my terminals are actually of the form:
>
> future_expresion<typename boost::proto::terminal<std::future&>::type>
>
> (where future_expression is the expression wrapper). Can I do this?
> Obviously I still have a problem if I do:
>
> std::future<int> fint = ...
> auto sum = ns::compose(fint) + 3;
> // then use sum.get()
>
> don't I?

Yes.

> I can't solve it by using proto::deep_copy since std::future is
> move-only (apparently my terminals get stripped of their reference).
> This means that the 'correct' way of doing the above would be
>
> std::future<int> fint = ...
> auto const operand = 3;
> auto sum = ns::compose(fint) + operand;
> // use sum.get()
>
> thus separating lifetimes from computations (expression trees, really).

And that doesn't solve the problem completely, because intermediate
expression nodes are also held by reference. Expressions any larger than
this will be UB.

<snip>
> Any idea?

As you have learned, Proto is not move-aware. My hand-wavy solution
would be to (a) be sure that everything is held by value in an ET. With
1.42, that's by using proto::by_value_generator. In 1.44, the preferred
solution is with a domain-specific as_child implementation. And (b) to
wrap move-only types in a "copyable" type that, in its copy ctor, moves
the wrapped value.

I'll see if I can come up with an example that demonstrates.

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

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net