
On Wed, Apr 2, 2008 at 6:18 AM, shunsuke <pstade.mb@gmail.com> wrote:
shunsuke wrote:
If fold_ is DefaultConstructible and a default-constructed one is callable, it would be:
typedef static_< mpl::always< return_of<T_regular(fold_(reverse_(T_bll_1), T_bll_2, T_bll_3))>::type > > reverse_fold;
Sorry, this never works. T_regular was pointless.
May be I shouldn't have used regular, but I want a way to stop a lambda expression from being, well, a lambda expression (so that I can compose it). I'll give you my use cases: In my framework (which unfortunately I do not own), I can define a fold function like this (BTW, such a macro would be a great addition to Egg): DEFUN(fold, (range)(init)(op), *(init) ){ // you can access the argument types via range_type, init_type and op_type. // result_type here is automagically defined as result_of<fold(range_type&, init_type&, op_type&)>::type result_type result = std::accumulate(boost::begin(range), boost::end(range), init, op); return result_type; } [the syntax is shamelessly stolen from boost.parameters] This will define a function object type named 'fold' in namespace 'meta' called range and an instance of this type, also named 'fold', in namespace 'algo' (the namespace names are more or less for historical reasons and do not really make much sense; also making this work in the face of ADL is a pain). Note that the third argument of the macro defines the result type. If you prefix it with a '*', you can pass an MPL expression instead of an actual type: in this context 'init' is the same as mpl::_2 (the macro takes care to rename the placeholders as the argument types). 'defun' does automatically perfect forwarding of its arguments as you would expect, and of course is both result_of and lambda compatible. It can also automatically participate in pipelines. Finally you can use the same object as a normal function object and in lambda expressions without the need for bind: normal function (non lazy): fold(my_range, 0, plus); used in a lambda expression (the first fold is not lazy, the second is lazy): fold(my_range_of_range, 0, lambda[ fold(_2, _1, lambda[ _1 + _2]) ] ); The library uses some magic to figure out if you want a lazy fold or not. Note that if you pass a lambda expression to fold, you must always wrap it with 'protect': fold(my_range, 0, _1 + _2) ; // illegal: the whole statement is a lazy expression and is not executed! fold(my_range, 0, protect(_1 + _2)); // good, now the scope for _1 and _2 is limited. The call to 'fold' is not lazy. // same as above, but I find it more readable. Also makes the lambda result_of // compatible and 'regular' (also does perfect forwarding with old versions of // boost.lambda). fold(my_range, 0, lambda[ _1 + _2]); I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
In fact, Egg secretly has its own usable placeholders, though.
Secretly? You mean that T_bll_1 and firends are not really boost.lambda placeholder types? Or you have something else in mind? Please elaborate... [1] A reason not to have optionally lazy functions is that if you forgot to protect a lambda, the entire expression might become a big lambda expression. OTOH, except for a top level for each, I always use the result of my function objects as they are otherwise side-effect free, so such errors would be easily caught by the compiler (result type mismatch). -- gpd