|
Boost Users : |
From: Simon Buchan (simon_at_[hidden])
Date: 2005-09-22 05:37:28
tom gee wrote:
> Hello Bjorn,
>
> Thanks for such a quick help. I works now.
>
> Can you please further explain the usage of var and constant .
> in the expression
> if_(_1 < 24.000001 && _1 > 23.999999)[ cout <<"Bingo:<"<<_1<<">"])
> I understand "Bingo:<" is evaluated immediately, why not ">", which is not a
> lambda expression either, is not
> evaluated along.
>
Refresher course: an expression like:
cout << foo << bar << endl;
is read (aka parsed) by the compiler to be shorthand for the following:
(((cout << foo) << bar) << endl);
which, incidently is just shorthand for:
operator<<(operator<<(operator<<(cout, foo), bar), endl);
Thus, '<<' is known as a 'left assosiative' (I think :D) operator.
Refresher over.
Basicly, the 'cout << "Bingo:<"' sub-expression has no 'lambda stuff' in
it, and therefore calls the _normal_ operator<<, which immediately
prints "Bingo:<". This operator<< returns a reference to cout, so the
next '<<' sees:
cout << _1
Which (obviously) is an expression containing a lambda (sub-)expression.
The guys who made this library were nice enough to provide overloads of
'<<' (along with every other possible operator) that return a 'lambda
function object', you just have to know that it is a valid lambda
expression that _will_ evalute as "cout << _the_first_argument_" when
called. The same happens with the next <<, it sees:
_lambda_operator_left_shift_ << ">"
, where the left argument is the previous lambda function object made
from the "cout << _1" sub-expression. Now there is _another_ overload of
<< that creates _another_ lambda function object, that _will_ evalute as
if it was:
cout << _the_first_argument_ << ">"
So, basicly, anytime there is a sub-expression that doesn't have a
lambda object in it, it is treated as a normal expression, but if it
does, it creates a function object that will do what it looks like it
would do. What 'constant' and 'var' do is make a (lambda?) function
object that just returns it's argument, as, respectively, a constant
copy, or a reference to the original (I think, again, use boost::ref to
be sure)
> Forgive me if this question seems stupid, but I am new to Lambda, fascinated
> by its power, but convoluted by its mechanism yet.
>
> Thanks.
>
[snip]
Don't worry about it, but don't forget to read the documentation!
One more thing to keep in mind, the overload for '()', the call
operator, for a lambda function object immeadiatly evaluates it's
contained expression, ie:
(_1 + 3)(4) == (4 + 3);
to get around this if you want to delay a call to that object, use:
boost::lambda::bind(_1 + 3, 4);
which returns a lambda function object that when called, calls the first
argument with the rest of bind's arguments as it's arguments, so:
bind(_1 + 3, 4)() == (_1 + 3)(4) == (4 + 3)
Which is VERY usefull if you want to, say call functions in a STL container:
int i, j;
std::vector<void(*)(int, int)> some_funcs;
...
std::for_each(some_funcs.begin(), some_funcs.end(), bind(*_1, i, j));
Although, Boost.Signals is probably a better bet if you do stuff like
that a bit.
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