Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] const-ness of references
From: Eric Niebler (eric_at_[hidden])
Date: 2010-03-03 21:48:00


On 3/4/2010 11:43 AM, Manjunath Kudlur wrote:
> Similar problem seems to exists for expression of the form
> Program_(a)(10). Here, Program_ is a function that returns
> proto::function<proto::terminal<program_>,
> proto::terminal<Var<proto::_> > >.

Not quite. See below.

<snip>
> template<typename VT>
> struct Var {
> VT value;
> void assign(const VT v) {
> value = v;
> }
> };

Var is a value-type. It holds a datum by-value.

> template<typename A0>
> typename proto::result_of::make_expr<proto::tag::function
> , program_domain
> , program_
> , A0 const&>::type const
> Program_(A0 const&a0)
> {
> return proto::make_expr<proto::tag::function, program_domain>(
> program_(),
> boost::ref(a0)
> );
> }

Program_ takes its argument by const ref. It's argument is therefore
immutable.

<snip>
> typedef proto::terminal<Var<int> >::type int32_;
>
> int main()
> {
> int32_ a,b,c;
>
> assign()(a=20);
> assign()(a(30));
>
> Program_(a)(10);

Here, we're passing "a" to Program_, which takes its argument as const
ref. Later, you extract "a" from the Proto tree and try to mutate it.
But it's const; obviously that's not going to work.

So the first thing you need to do is change Program_ to take its
argument by non-const ref. However, when you do that, you'll find that
it still doesn't work. And that has to do with how proto::make_expr works.

proto::make_expr tries to enforce uniformity in the trees it returns. In
particular, it wants all the child nodes to be in the same domain as the
parent node it returns. When the domains don't match (as they don't in
this case because int32_ is in the default_domain), it passes the child
through the domain's generator. The result gets stored by value instead
of by reference as you're requesting.

The fix is quite simple. Define int32_ as follows:

   typedef proto::literal<Var<int>, program_domain> int32_;

That puts it in the program_domain.

Also, you should note that your generator is broken. It only handles the
function<terminal,terminal> case. Passing any other expression to it
violates its preconditions. You need an otherwise<_> in there.

(BTW, I just added a default constructor to literal to make your code
compile.)

-- 
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