// (by Ariel Badichi) #include <boost/static_assert.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/add_pointer.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/lambda.hpp>

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

template<typename F, typename T> struct twice : mpl::apply<F, typename mpl::apply<F, T>::type> {};

int main() { typedef mpl::lambda<boost::add_pointer<_> >::type add_pointer_lambda; typedef twice<twice<add_pointer_lambda, _>, int>::type p;

BOOST_STATIC_ASSERT((boost::is_same<int ****, p>::value));

return 0; }

Can anyone explain why the explicit lambda call is necessary? I had thought that the apply embedded in twice would deal with the add_pointer placeholder expression, but GCC 3.3.3 gives a compile error with the following:

BOOST_STATIC_ASSERT(( boost::is_same< twice< twice< boost::add_pointer<_1>, // needs to be wrapped in mpl::lambda<...>::type ??? _1 >, int >::type, int**** >::value ));

Any ideas? -- Matt Brecknell

*Section 3.3 has a nice explanation for why this won't work.* - Ariel

*Matt*: Section 3.3 does explain why versions of the *twice* metafunction from earlier sections of the book don't work directly with placeholder expressions. But then section 3.3.2 says *the first argument to mpl::apply can be any lambda expression (including those built with placeholders)*. Since your definition *twice* uses *mpl::apply* to invoke the argument metafunction, I expected to be able to use placeholder expressions without needing to use *mpl::lambda*. For example, I believe the following should work with your definition of *twice* (though I'm not in front of an MPL-capable compiler at the moment, so I can't check):

BOOST_STATIC_ASSERT(( boost::is_same< twice< boost::add_pointer<_>, // no mpl::lambda required here int >::type, int** >::value ));

I'm currently working on the theory that the problem with my version of the nested invocation of *twice* might be something to do with the way the outer *twice* is evaluating placeholders in the inner *twice*, but I haven't figured it out yet. -Matt

*In your previous snippet, consider the inner twice first. Consider the second argument. It's just the type _1. It's nothing special in the context of the inner twice. Therefore, the result of the inner twice is _1 **. The inner twice is a metafunction, not a lambda expression. So you can't mpl::apply it. If you use mpl::lambda on boost::add_pointer, then the inner twice will use it to generate a lambda expression, which can be passed to mpl::apply, and therefore to the outer twice. At least I think that's how it goes (I wonder if Dave could clear this up?)* - Ariel

I agree that the inner *twice<>* would evaluate to *_1*** if I had immediately evaluated the inner *twice<>* with *::type*. But since I didn't, I thought that the outer *twice<>* would regard the inner *twice<>* as a placeholder expression (and not just a metafunction, as you then suggest). I therefore expected that the *mpl::apply* in the inner *twice<>* would convert the *boost::add_pointer<_1>* to a metafunction class, while leaving the second argument (bare *_1*) for the outer *twice<>* to substitute. That's why I used *_1* in both places, even though they are meant to refer to different things in different contexts. In any case, I don't see why your reasoning would apply to my formulation, without also applying to yours. After all, you have a "_" placeholder in the same place in your version. The only material difference is that you have wrapped *boost::addpointer<_>* in *mpl::lambda<>*. I don't follow your reasoning about *mpl::lambda* causing the inner *twice<>* to "generate a lambda expression" for the outer *twice<>*: if the inner *twice<>* is a placeholder expression, then it's already a lambda expression (book section 3.6). Obviously, my reasoning has gone wrong somewhere, but I'm not yet convinced it's for any of the reasons you have suggested. -Matt

*I accept that the inner twice is a placeholder expression. The outer twice then substitutes BOTH placeholders for a type (for each mpl::apply). Using mpl::lambda protects the placeholder for boost::add_pointer from substitution. How this works exactly, I'm not sure.* - Ariel

The reason `twice< twice< add_pointer<_1>, _1 >, int >` doesn't work
is that, without an explicit scope specification,
`mpl::apply< twice< add_pointer<_1>, _1 >, int >::type`
is equivalent to

template< typename T > struct twice_add_pointer : twice< typename add_pointer<T>::type, T > { };

mpl::apply< twice_add_pointer<_1>, int >::type

which, I hope, is clearly erroneous. With explicit scoping along the lines of http://thread.gmane.org/gmane.comp.lib.boost.devel/115924, a working one-liner would be

twice< twice< scope< add_pointer<_1> >, _1 >, int >

Hope this clarifies things, People/Aleksey Gurtovoy.

Disclaimer: This site not officially maintained by Boost Developers