Boost logo

Boost :

From: Andrei Alexandrescu (andrewalex_at_[hidden])
Date: 2002-05-01 22:46:53


I don't really understand how this hasn't occured to anyone yet, it's
an
obvious trick. I recall it occured to me at some point but then the
synapse
wasn't strong enough or something. Also, I saw a very similar trick,
if not the very same trick (can't check now, I'm on a very slow
connection) in compressed_pair.

The idea is to use derivation only for those policies that are
nonempty, and
to simply not derive at all from policies that are empty. Then, when
using
policies inside smart_ptr, you use the base accessor syntax, for
example:

    ... inside smart_ptr ...
    void operator->()
    {
        SomePolicy::DoSomething(args);
    }

The enabling "technology" is that the syntax above works both when
SomePolicy is a base and DoSomething is a static or nonstatic member
function of it, or when SomePolicy is not a base function and
DoSomething is a static member function of it.

Consequently, an empty nonmember and a nonempty base can be treated in
the
same way.

This doesn't introduce any limitation of expressiveness, because if a
class
has no state, there's not much point to writing nonstatic member
functions
for that class.

So all we need is the following:

1) A device that detects whether a class is empty or not. I believe
that's
already in boost's type_traits (is_empty).

2) A device that optionally inherits one, the other, or both of two
classes depending whether the first, the second, or both are nonempty.
Something like:

template <class T, class U,
    bool forceInheritT = !type_traits<T>::is_empty,
    bool forceInheritU = !type_traits<U>::is_empty>
struct OptionallyInherit : public T, public U
{
    template <class V, class W>
    OptionallyInherit(const U& obj1, const W& obj2)
    : T(obj1), U(obj2)
    {
    }
};

// Inherit none; both are empty
template <class T, class U>
struct OptionallyInherit<T, U, false, false>
{
    template <class V, class W>
    OptionallyInherit(const V&, const W&)
    {
    }
};

// Inherit U; T is empty
template <class T, class U, >
struct OptionallyInherit<T, U, false, true> : public U
{
    template <class V, class W>
    OptionallyInherit(const V&, const W& obj2)
    : U(obj2)
    {
    }
};

// Inherit T; U is empty
template <class T, class U, >
struct OptionallyInherit<T, U, true, false> : public T
{
    template <class V, class W>
    OptionallyInherit(const V& obj1, const W&)
    : T(obj1)
    {
    }
};

If I'm not mistaken, OptionallyInherit<T> as defined above "minimizes"
inheritance in that it inherit either of its arguments iff that
argument is nonempty. Many details can be refined. It is also possible
that compressed_pair does exactly what OptionallyInherit does, which
means we can use it out-of-the-box for policy packing!

Now when defining smart_ptr, the policies come wrapped in
OptionallyInherit:

    template
    <
        typename T,
        template <typename> class OwnershipPolicy,
        template <typename> class ConversionPolicy,
        template <typename> class CheckingPolicy,
        template <typename> class StoragePolicy
>
    class smart_ptr
        : public OptionallyInherit<
            StoragePolicy<T>,
            OptionallyInherit<CheckingPolicy<
                    typename StoragePolicy<T>::stored_type> >,
                OptionallyInherit<OwnershipPolicy<
                        typename StoragePolicy<T>::pointer_type> >,
                    OptionallyInherit<ConversionPolicy<
                        typename StoragePolicy<T>::pointer_type> > > >
    {
        ...
    };

Doesn't look terribly intuitive, but it's library code. The client
code stays as nice as it was. But now we got (1) orthogonal policies
and (2) no size overhead.

Now that the issue is past us, we can compare the layered policy
design with the orthogonal policy design better, without our view
being biased by the pessimization introduced by the latter design. It
is still unclear (to me at least) which design is better; it seems
like both have advantages and disadvantages.

Anyway - we made a step forward.

Andrei


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk