[Home]CPPTM Answers - Exercise 3-6

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

 // (by Ariel Badichi)
 #include <boost/static_assert.hpp>
 #include <boost/mpl/placeholders.hpp>
 #include <boost/mpl/apply.hpp>
 #include <boost/mpl/int.hpp>
 #include <boost/mpl/plus.hpp>
 #include <boost/mpl/lambda.hpp>

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

 struct twice_lambda
 {
     template<typename F, typename X>
     struct apply : mpl::apply<F, typename mpl::apply<F, X>::type> {};
 };

 int main()
 {
     typedef mpl::int_<5>::type five;
     typedef mpl::plus<_1, _1> unary_plus;

     BOOST_STATIC_ASSERT((mpl::apply<twice_lambda, unary_plus, five>::type::value == 20));

     return 0;
 }


I tried to solve this problem using placeholder expressions, and ran into a surprise (for me at least). The following code works, as I had hoped:

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

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

 struct add_ptr_f
 {
   template <class T>
   struct apply: boost::add_pointer<T>{};
 };

 template <class F, class X>
 struct apply1 : F::template apply<X>
 {
 };

 int main()
 {
   BOOST_STATIC_ASSERT((boost::is_same<
         mpl::apply< mpl::lambda<apply1<_1,apply1<_1,_2> > >, add_ptr_f, int>::type,
         int**>::value
      ));
 }

However, when I try to use boost::mpl::apply instead of apply1, I get some nifty errors. Even if I only try to use mpl::apply once, as in

 BOOST_STATIC_ASSERT((boost::is_same<
      mpl::apply< mpl::lambda<mpl::apply<_1,_2> >, add_ptr_f, int>::type,
      int*>::value
      ));

then gcc3.4 spits out the following errors (first 2 only):

 /usr/local/include/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:49: error: no class template named `apply' in `struct    boost::mpl::lambda<boost::mpl::apply<mpl_::_1, mpl_::_2, mpl_::na, ...>'
 3-6.C:39: error: `type' is not a member of `boost::mpl::apply<boost::mpl::lambda<boost::mpl::apply<mpl_::_1, mpl_::_2, mpl_::na, ...>'

I'm confused as to why that doesn't work. Can anyone enlighten me? --mahall


the problem is that you didn't use "::type" for nested "mpl::apply<...>" so, we receive:

	BOOST_STATIC_ASSERT((
	    boost::is_same<
	        mpl::apply<mpl::lambda<mpl::apply<_1, _2>::type>, add_ptr_f, int>::type,
	        int*
	    >::value
	));

the bad news is that it can be compiled but doesn't work as expected, the result is "int", not "int*". I think the reason is placeholders substitution time but cannot explain why. Really, using handmade apply1 works well because can be used w/o "::type". Try

	BOOST_STATIC_ASSERT((
	    boost::is_same<
	        mpl::apply<mpl::lambda<mpl::apply<_1, _2>::type>, add_ptr_f, int>::type,
	        int*
	    >::value
	));

It doesn't work for the same reason that the previous example. So what is the difference between apply1 and mpl::apply and why if they are so similar, apply1 can be used w/o "::type" and mpl::apply cannot be? Because mpl::apply is partial template specialization. Details? I don't know, really.

As result, following version:

	typedef mpl::lambda<
	    mpl::apply<
	        mpl::_1, 
	        mpl::apply<_1, _2>::type
	    >::type
	>::type twice;
	BOOST_MPL_ASSERT((boost::is_same<mpl::apply<twice, boost::add_pointer<_>, int>::type, int**>));

doesn't work.

Another working solution I've received looks like:

	BOOST_MPL_ASSERT((
	    boost::is_same<
	        mpl::apply<
	            boost::add_pointer<_>, 
	            mpl::apply<boost::add_pointer<_>, int>::type
	        >::type, 
	        int**
	    >
	));

but doesn't allow to separate "boost::add_pointer<_>".

Andriy Tylychko, telya at mail dot ru



BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited July 21, 2006 9:49 am (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers