Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-05-19 23:38:46


Larry Evans wrote:
> On 05/19/08 18:51, Eric Niebler wrote:
>> Um, does this mean you're using the proto/v4 branch?
>
> Yes.
>
>> Are you still having problems, or have they gone away?
>
> They're still there.
>
>> Can you send a compiler error and steps to repro? 'Cause it works over
>> here.
>>
> The attachment on 1st post has '#if 1' around line 117. That should
> produce the error. The 2nd post's attachment has '#if 0' and doesn't
> produce an error. When you run, do you use '#if 1' or not?
>
> The complete bjam output of 2nd post's attachment with '#if 1' is
> attached as bjam.out.

Ah, you're using gcc. I see the error now. I'm sorry to say this
behavior is by-design -- at least until we get rvalue references --
although there are simple work-arounds. Let me explain.

A Proto transform takes an expression tree as its first argument. The
signature is something like this:

   // take expr, state and data by non-const ref
   template<class Expr, class State, class Data>
   typename result<void(Expr &, State &, Data &)>::type
   operator()(Expr &expr, State &state, Data &data) const

   // an overload for a const state parameter.
   template<class Expr, class State, class Data>
   typename result<void(Expr &, State const &, Data &)>::type
   operator()(Expr &expr, State const &state, Data &data) const

Note that expressions are taken by non-const reference. They must be
lvalues or const-qualified rvalues. That's usually the case, but not for
your code. (The data parameter is handled similarly, but there are other
overloads so you don't have to specify it.)

You might think I could just add an overload that takes an expression by
const reference to solve the problem. But that introduces another. To do
overload resolution, the compiler would need to calculate the return
type for both overloads, and for some expressions, the return type
calculation will fail if the expression is const-qualified. (A transform
could mutate an expression tree in-place. The expression tree had better
not be const.) So even if you never actually pass a const expression
tree, the mere presence of the overload will cause the compile to fail.
Very frustrating.

So that's the reason why. You can work around the error by making sure
you pass only lvalue expression trees or const-qualified rvalue
expression trees to transforms. You can do that by converting a
non-const rvalue into a const lvalue by passing it through a dummy
as_lvalue() function like:

template<class T> T const & as_lvalue(T const &t) { return t; }

When I do that, I hit another error in your code having to do with an
ambiguous conversion sequence. Doesn't look like a Proto problem, though.

HTH,

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk