[Home]CPPTM Answers - Exercise 3-7

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

 // (by Ariel Badichi)
 #include <iostream>
 #include <vector>

 #include <boost/static_assert.hpp>
 #include <boost/type_traits/is_same.hpp>
 #include <boost/type_traits/add_pointer.hpp>
 #include <boost/mpl/placeholders.hpp>
 #include <boost/mpl/apply.hpp>
 #include <boost/mpl/lambda.hpp>
 #include <boost/mpl/plus.hpp>
 #include <boost/mpl/minus.hpp>
 #include <boost/mpl/int.hpp>

 namespace mpl = boost::mpl;
 using namespace mpl::placeholders;

 int main()
     // (I'm adding lines one by one with comments that say what I think every
     //  line does)

     // This is a metafunction class, generated using the Lambda facility.
     // The metafunction held by the metafunction class receives one
     // argument. It will generate a metafunction class from that argument.
     // (the argument must be a lambda expression)
     typedef mpl::lambda<mpl::lambda<_1> >::type t1;

     // Here I will invoke the metafunction in the metafunction class, which is
     // mpl::lambda<_1>.
     typedef t1::template apply<boost::add_pointer<_> >::type addptr_f;

     // Now that I have generated a metafunction class from the lambda
     // expression boost::add_pointer<_>, I can use it:
     BOOST_STATIC_ASSERT((boost::is_same<mpl::apply<addptr_f, int>::type, int *>::type::value));

     // Yep. First done, on to the next one!

     // Here we use the metafunction mpl::apply. We pass a metafunction and
     // an argument. I think this is an error, because having _1 as the first
     // argument will cause infinite recursion (or more likely, an MPL
     // static assertion)
     typedef mpl::apply<_1, mpl::plus<_1, _2> >::type t2;

     // OK, I try this:
     typedef mpl::int_<1> one;
     BOOST_STATIC_ASSERT((mpl::apply<t2, one, one>::type::value));

     // It seems to compile. But what is the value? Let's see:
     std::cout << mpl::apply<t2, one, one>::type::value << "\n";

     // The value is 2. OK, so now I think mpl::apply's function is
     // the mpl::plus<_1, _2> and the arguments passed in the enclosing
     // mpl::apply are passed to plus. Let's try:
     typedef mpl::int_<2> two;
     BOOST_STATIC_ASSERT((mpl::apply<t2, one, two>::type::value == 3));

     // So far so good. Let's see that the order is right:
     typedef mpl::apply<_1, mpl::minus<_1, _2> >::type t2_;
     BOOST_STATIC_ASSERT((mpl::apply<t2_, two, one>::type::value == 1));

     // Arf. That was a (mildly?) tricky one. Let's continue.

     // From last experiment, we know the _1 causes the lambda facility to
     // evaluate the second argument. In this case, the second argument is a
     // non-metafunction.
     typedef mpl::apply<_1, std::vector<int> >::type t3;

     // So I think the result is std::vector<int> itself, thus t3 is a
     // std::vector<int>.
     BOOST_STATIC_ASSERT((boost::is_same<t3, std::vector<int> >::type::value));

     // Aah. Correct we are. Next!

     // Since now our std::vector is passed to the lambda facility, I believe
     // t4 is a metafunction class, whose result is std::vector<argument>.
     typedef mpl::apply<_1, std::vector<_1> >::type t4;

     // Let's try:
     typedef mpl::apply<t4, int>::type t4result;
     BOOST_STATIC_ASSERT((boost::is_same<std::vector<int>, t4result>::type::value));

     // Correct again.

     // First we swap _1 for std::vector<int>, so we have a lambda facility
     // specialized with the std::vector<int>. So I suspect t5 is actually the
     // lambda facility, and we need to get its resulting ::type.
     typedef mpl::apply<mpl::lambda<_1>, std::vector<int> >::type t5;

     // I think the resulting type is std::vector<int>, since it's not a metafunction.
     // typedef t5::type t5result;
     // BOOST_STATIC_ASSERT((boost::is_same<std::vector<int>, t5result>::type::value));

     // Er, nope. It seems that t5 IS a std::vector<int>.
     BOOST_STATIC_ASSERT((boost::is_same<std::vector<int>, t5>::type::value));

     // Hmmm, so apply applies lambda facility to _1, which creates the 
     // specialization, then apply applies the lambda itself, which results in
     // the std::vector<>. Next problem...

     // Alright. We apply _1 in the first argument, so we have 
     // mpl::lambda<std::vector<_1> >.. then we apply it. The result is
     // a metafunction class, which we need to apply to get a std::vector.
     typedef mpl::apply<mpl::lambda<_1>, std::vector<_1> >::type t6;

     typedef mpl::apply<t6, int>::type t6result;
     BOOST_STATIC_ASSERT((boost::is_same<t6result, std::vector<int> >::type::value));

     // Right.

     // Ah, I think the usual case here. We apply _1 for first argument:
     // mpl::apply<mpl::lambda<mpl::plus<_1, _2> > >. The result is a
     // metafunction class for plus.
     typedef mpl::apply<mpl::lambda<_1>, mpl::plus<_1, _2> >::type t7;

     // We apply our metafunction class with two arguments:
     BOOST_STATIC_ASSERT((mpl::apply<t7, one, two>::type::value == 3));

     // Yes. This is getting easy ;). Last problem:

     // OK, a bit more tricky. So first we evaluate the first argument, which
     // results in mpl::apply<mpl::lambda<mpl::plus<_1, _2> > >.
     // This applies lambda evaluation to plus. In effect, seems like last
     // problem?
     typedef mpl::apply<_1, mpl::lambda<mpl::plus<_1, _2> > >::type t8;

     BOOST_STATIC_ASSERT((mpl::apply<t8, one, two>::type::value == 3));

     // Yaargh! :)

     return 0;

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited March 26, 2005 8:09 am (diff)
Disclaimer: This site not officially maintained by Boost Developers