|
Boost : |
From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2002-10-04 06:35:06
David B. Held wrote:
> > Of course, the fourth way would be this:
> >
> > 4)
> > // policies are still ordinary class templates, but with
> > // arbitrary number and order of template parameters
> >
> > template< typename T >
> > struct ownership_policy1
> > {
> > //...
> > };
> >
> > template< typename P1, typename T, typename P2 > // here
> > struct ownership_policy2
> > {
> > //...
> > };
> >
> > template< typename T >
> > struct conversion_policy2
> > {
> > //...
> > };
> >
> > // use MPL's lambda:
> >
> > typedef smart_ptr< my
> > , ownership_policy1<_>
> > , conversion_policy1<_>
> > , ...
> > > my_ptr;
> >
> > typedef smart_ptr< my
> > , ownership_policy2<param1,_,param2> // here!
> > , conversion_policy1<_>
> > , ...
> > > my_ptr2;
> >
> > The 'smart_static_cast' implementation still would be the
> > same as above (the sane one!).
>
> ...needs some explaining! I have a vague notion that MPL::lambda is
> "currying a metafunction"?
Yes, in the simplest case; basically you spell out a metafunction with some
arguments filled and some missing:
typedef is_same<_,int> f;
and MPL allows you to convert it to metafunction-class - and after that you
can do whatever you want with it:
template< typename Predicate > struct my
{
// turn 'Predicate' into a metafunction-class
typedef typename mpl::lambda<Predicate>::type pred_;
// now we can apply it!
typedef mpl::apply<pred_,int>::type res_;
};
BOOST_STATIC_ASSERT(my<f>::res_::value)
There are two things worth mentioning about this example:
a) the ability of 'my' template to handle lambda expressions doesn't affect
its ability to work with ordinary, "plain" metafunction-classes:
struct always_true
{
template< typename T > struct apply
: mpl::true_c
{
};
};
// no problem!
BOOST_STATIC_ASSERT(my<always_true>::res_::value)
b) lambda expressions might be much much more complicated
typedef or_<
is_same<_,int>
, equal< sizeof_<_>, sizeof_< add_pointer<_> >
> f2;
and yet you don't need to change 'my' implementation in any way in order to
make it handle something like the above - it just works:
// no problem as well
BOOST_STATIC_ASSERT(my<f2>::res_::value)
> It is producing a unary metafunction class?
A metafunction class, yes. The arity depends on the arity of the original
lambda expression, obviously:
typedef lambda< plus<_,_,_,_> >::type f4; // arity == 4
typedef lambda< plus<_,int_c<5>,_,_> >::type f3; // arity == 3
typedef lambda< is_same<_,_> >::type f2; // binary
typedef lambda< is_same<void,_> >::type f1; // unary
typedef lambda< ownership_policy1<_> >::type g1; // unary
> You lost me on how this gets implemented.
Oh, that's easy - here's how the definition of a smart pointer template that
accepts only plain metafunction-class parameters might look like:
template <
typename T
, typename OwnershipPolicy
, typename ConversionPolicy
, typename CheckingPolicy
, typename StoragePolicy
, typename sp_ = typename apply<StoragePolicy,T>::type
>
struct smart_ptr
: sp_
, apply<OwnershipPolicy, typename sp_::pointer_type>::type
, apply<CheckingPolicy, typename sp_::pointer_type>::type
{
// ...
};
// usage
struct ownership_policy1 // policies are metafunction-classes
{
template< typename T > struct apply
{
//...
};
};
// ...
typedef smart_ptr< my
, ownership_policy1
, conversion_policy1
, ...
> my_ptr;
And here's an equivalent definition that accepts both meta-function classes
and lambda expressions:
template< typename F, typename T > struct le_apply
{
typedef typename mpl::lambda<F>::type f_;
typedef typename mpl::apply1<f_,T>::type type;
};
template <
typename T
, typename OwnershipPolicy
, typename ConversionPolicy
, typename CheckingPolicy
, typename StoragePolicy
, typename sp_ = typename le_apply<StoragePolicy,T>::type
>
struct smart_ptr
: sp_
, le_apply<OwnershipPolicy, typename sp_::pointer_type>::type
, le_apply<CheckingPolicy, typename sp_::pointer_type>::type
{
// ...
};
// usage
// policies can have form of both ordinary class templates...
template< typename T >
struct ownership_policy1
{
//...
};
// ...and metafunction-classes
struct conversion_policy1
{
template< typename T > struct apply
{
//...
};
};
// ...
typedef smart_ptr< my
, ownership_policy1<_>
, conversion_policy1
, ...
> my_ptr;
// and they can take pretty sophisticated forms as well
typedef smart_ptr< my
, ownership_policy1< add_const< add_pointer<_> > >
, conversion_policy1
, ...
> my_const_ptr;
> In fact, that code looks like pure magic to me...
It's because it is pure magic :).
> I have no idea how to go from what you wrote to
> something my compiler will recognize. ;)
If we are talking about Borland, my local copy of the library passes all but
3 tests (of 54), so don't worry about that :).
> Before I go converting everything to canonical template form or whatever,
> I could really use a bit of a tutorial on what's going on above.
Well, I hope the above clarifies things a little bit.
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk