
Hi Nicholas, On Fri, 13 Jan 2012 19:44:07 -0600, Kitten, Nicholas <nkitten@objectvideo.com> wrote:
I've recently been doing a lot mpl::folding (in boost 1.47), and I was disappointed when I realized that a nested fold wouldn't work with a lambda expression passed to the inner call, as in this example which extracts elements of sequences:
using namespace mpl; using namespace mpl::placeholders;
typedef vector< vector<char>, vector<int> > vec_of_vecs; typedef vector< char, int > expected_result;
typedef fold< vec_of_vecs, vector<>, fold< _2, _1, *push_back< _1, _2 >* // wrong - refers to outer arguments >
::type result;
BOOST_MPL_ASSERT(( equal<result, expected_result> ));
After looking around for a solution I came across an old thread<http://lists.boost.org/boost-users/2004/12/9269.php> on the same subject, where it was suggested using mpl::protect might work. Indeed, the following modification does what I want, without any changes to the library:
typedef fold< vec_of_vecs, vector<>, fold< _2, _1, *protect< lambda< push_back< _1, _2 >
::type * // correct > ::type result;
Actually, you don't need 'protect' here, plain 'lambda< push_back< _1, _2
::type' would suffice, the resulting Metafunction Class is already shielded from being interpreted as a placeholder expression. Or you can just go with simple 'quote2<push_back>'.
Of course, this is a little on the verbose side. In the old thread, Daniel Wallin suggested suggested changing the definition of lambda to yield syntax more in line with the runtime version of boost::bind, but that would apparently break other code.
Yes, Daniel's suggestion affects not only protect's syntax, but also its semantics.
What about instead adding a specialization to protect for placeholder expressions? Indeed, the source in protect.hpp seems to indicate such a thing might've been in the works at one point,
Nope :), please see below.
but I didn't see any more references to it:
template< typename BOOST_MPL_AUX_NA_PARAM(T) * , int not_le_ = 0 // not lambda expression?* > struct protect : T { ... typedef protect type; };
That parameter's name is somewhat misleading; what it actually means is something like "this is an non-type template parameter that prevents 'protect' from being treated as a placeholder expression".
What about changing it to something like this?
template< typename BOOST_MPL_AUX_NA_PARAM(T) * , typename not_le_ = typename is_lambda_expression< T >::type* > struct protect : T { ... typedef protect type; };
*template< typename T >* *struct protect< T, mpl::true_ > : lambda<T>* *{* *...* *typedef protect type;* *};*
If we are try this, it would need to be more along the lines of template< typename BOOST_MPL_AUX_NA_PARAM(T) , bool not_le_ = is_lambda_expression<T>::value > struct protect : T { typedef protect type; }; template< typename T > struct protect<T,true> : lambda<T>::type { typedef protect type; }; .. but I'm pretty sure it's still going to break at least some code. Hmm, let me try this quick... yep, breaks the library itself; check out the following code in "equal.hpp": template< typename Predicate , typename LastIterator1 , typename LastIterator2 > struct equal_pred // Metafunction class! { template< typename Iterator2 , typename Iterator1 > struct apply { ... }; }; template< typename Sequence1 , typename Sequence2 , typename Predicate > struct equal_impl { typedef typename begin<Sequence1>::type first1_; typedef typename begin<Sequence2>::type first2_; typedef typename end<Sequence1>::type last1_; typedef typename end<Sequence2>::type last2_; typedef aux::iter_fold_if_impl< first1_ , first2_ , next<> , protect< aux::equal_pred<Predicate,last1_,last2_> > // <---- here , void_ , always<false_> > fold_; See how the suggested specialization changes the meaning of the highlighted line? For it to work with the new 'protect' definition, the line needs to be changed to , aux::equal_pred< protect<Predicate>,last1_,last2_> > and the 'equal_pred' rewritten to take this into account. Doable, but the change is definitely not backward compatible. The thing is, 'protect' was really conceived w/ bind and Metafunction classes in mind, and it actually works as you'd expect in that context (see Example in http://www.boost.org/doc/libs/1_48_0/libs/mpl/doc/refmanual/protect.html). It might be possible to retrofit it to lambda expressions, but it'll require quite a bit of work that I'm not sure is worth it. Personally, I'd rather work on a more general scoping mechanism along the lines of http://article.gmane.org/gmane.comp.lib.boost.devel/116000 HTH, -- Aleksey Gurtovoy MetaCommunications Engineering