Boost logo

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