|
Boost : |
From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2002-10-03 03:12:23
David B. Held wrote:
> If anyone needs to be convinced that template templates are a good and
> useful feature of C++, let them take a look at this code, which is an
> adaptation of shared_static_cast for policy-based pointers:
>
> template <
> typename T,
> BOOST_SMART_POINTER_PARAMETERS,
> typename U
> >
> inline smart_ptr<T,
> typename OwnershipPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::pointer_type
> >::other,
> typename ConversionPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::pointer_type
> >::other,
> typename CheckingPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::stored_type
> >::other,
> typename StoragePolicy::template rebind<T>::other
> >
> smart_static_cast(
> smart_ptr<U, BOOST_SMART_POINTER_POLICIES> const& p
> )
> {
> return smart_ptr<T,
> typename OwnershipPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::pointer_type
> >::other,
> typename ConversionPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::pointer_type
> >::other,
> typename CheckingPolicy::template rebind<
> typename StoragePolicy::template
> rebind<T>::other::stored_type
> >::other,
> typename StoragePolicy::template rebind<T>::other
> >(
> p, detail::static_cast_tag()
> );
> }
>
> Note also that this code is somewhat simplified by macros I've been
> using, and that this technique requires *every policy* to
> define a rebind<>
> template. Also keep in mind that there are three other casts
> like this. :(
> What a high price to pay for lack of template templates!!
You are having the above troubles only because instead of "canonical"
transformation of template template parameters to metafunction-class
parameters:
1) before:
template< typename T >
struct ownership_policy1
{
//...
};
template< typename T >
struct conversion_policy1
{
//...
};
typedef smart_ptr< my
, ownership_policy1
, conversion_policy1
, ...
> my_ptr;
2) after:
struct ownership_policy1
{
template< typename T > struct apply
{
//...
};
};
struct conversion_policy1
{
template< typename T > struct apply
{
//...
};
};
typedef smart_ptr< my
, ownership_policy1
, conversion_policy1
, ...
> my_ptr;
the third, not-really-working way has been chosen:
3) a don't-go-there way:
template< typename T >
struct ownership_policy1
{
template< typename U > struct rebind
{
typedef ownership_policy1<U> type;
};
//...
};
template< typename T >
struct conversion_policy1
{
template< typename U > struct rebind
{
typedef ownership_policy1<U> type;
};
//...
};
typedef smart_ptr< my
, ownership_policy1<my>
, conversion_policy1<my>
, ...
> my_ptr;
You have seen for yourself where it leads to :).
If you choose 2) then your 'smart_static_cast' example would be at least as
good as a version that uses template template parameters:
template <
typename T,
BOOST_SMART_POINTER_PARAMETERS,
typename U
>
inline smart_ptr<T,BOOST_SMART_POINTER_PARAMETERS>
smart_static_cast(
smart_ptr<U, BOOST_SMART_POINTER_POLICIES> const& p
)
{
return smart_ptr<T,BOOST_SMART_POINTER_POLICIES>(
p, detail::static_cast_tag()
);
}
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!).
HTH,
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk