// (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; }