Boost MPL nested lambdas
Asked Answered
A

1

7

I have been trying to get to grips with Boost MPL.

As simple exercises, I tried:

typedef vector_c<int, 1, 2, 3, 4, 5>::type example_list;

typedef transform<example_list, times<_, int_<2> > >::type doubled_example_list;

typedef transform<example_list, negate<_> >::type negated_example_list;

BOOST_STATIC_ASSERT((at_c<negated_example_list, 2>::type::value==-3));
BOOST_STATIC_ASSERT((at_c<doubled_example_list, 4>::type::value==10));

These all work fine. However, the following attempt does not compile:

typedef transform<_, negate<_> > negate_a_list;

typedef apply<negate_a_list, example_list>::type negated_example_list_2;

BOOST_STATIC_ASSERT((at_c<negated_example_list_2, 2>::type::value==-3));

I think it is something to do with the scope of the placeholders in negate_a_list, however I am not sure how to fix it. Any ideas? I also suspect that some of my assumptions about the syntax and semantics of MPL are flawed. I would be grateful for any tips for grokking MPL.

P.S. Here is the preamble for the above code:

#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/times.hpp>
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/negate.hpp>
#include <boost/mpl/at.hpp>

using namespace boost::mpl;
using namespace boost::mpl::placeholders;
Aegaeon answered 18/4, 2013 at 16:2 Comment(2)
The problem is that the placeholders refer to two different levels of application: the first one need to be bound when calling apply, while the second must be bound when calling transform. In your code, negate_a_list is a binary metafunction, while it should be a unary metafunction returning a unary metafunction. Dealing with nested lambdas can be tricky, you may find some answers in this thread on the Boost mailing list.Ascending
Erratum: negate_a_list should not really "return a unary metafunction", it is rather some kind of encapsulation. Basically, what you have now is akin to this lambda (x, y) => transform(x, negate(y)) while you need (x) => transform(x, (y) => negate(y)).Ascending
A
5

Thanks to Luc Touraille's comment on my question, the Boost mailing list provides the answer. This code works:

typedef transform<_, lambda<negate<_> >::type > negate_a_list;

typedef apply<negate_a_list, example_list>::type negated_example_list_2;

BOOST_STATIC_ASSERT((at_c<negated_example_list_2, 2>::type::value==-3));

Note the addition of the lambda<...>::type wrapping around the lambda expression. This is sufficient to bound the scope of the placeholder.

Aegaeon answered 18/4, 2013 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.