|
Boost : |
From: David Abrahams (david.abrahams_at_[hidden])
Date: 2002-01-05 21:10:52
From: "Beman Dawes" <bdawes_at_[hidden]>
> At 03:58 PM 1/4/2002, David Abrahams wrote:
>
> >I have suggested several times that we look at the Policy Adaptor
pattern
> >used by the Iterator Adaptors Library. It certainly makes the problem of
> >policy interaction go away, since all of the policies are collected in
> one
> >place... but there have been no replies, and I am wondering why. Is it
> seen
> >as inappropriate for smart pointers? Are people having trouble
> >understanding the suggestion?
>
> I am. Every time you mentioned it (once in person, several other times in
> postings), I went back and read portions of the paper. In particular, the
> section below. How does it a apply to smart pointers? Smart pointers
> don't seem to have nice neat models of concepts like InputIterator,
> ForwardIterator, BidirectionalIterator, or RandomAccessIterator. Or if
> they did, there would be hundreds of them.
I don't think that really changes things much. The Policy Adaptor pattern
doesn't depend on having strictly-defined concept models any more than the
pattern used by Andrei does, AFAICT.
> I think the iterator example is
> confusing me. With smart pointers the starting point (in my mind) is a
> feature model. That translates nicely (as done by Andrei) into a set of
> policies, which are for the most part orthongonal.
The analogy with iterators is a fairly strong one. You could think of
writing an iterator library with dereference, motion, and comparison
policies, for example.
> Each of the policies
> has two or more default implementations, corresponding to the common
> feature variations for that Policy. I don't understand how to (usefully)
> mash the policies together into a single policy. I'm basically lost.
I think your nested inheritance model effectively does that, since the
SmartPtr is effectively derived from a single class which is a composition
of all of the policies:
template <
typename T,
template <class> class OwnershipPolicy,
template <class> class ConversionPolicy,
template <class> class CheckingPolicy,
template <class> class StoragePolicy >
class SmartPtr
: public ConversionPolicy <
typename OwnershipPolicy <
typename CheckingPolicy <
typename StoragePolicy<T> > > >
{ ...
A small variation might be all that's required to make it easier to build
policy interactions:
template <typename T, typename Policies>
class SmartPtr : public Policies
{
...
};
The Policy Adaptor pattern uses template member functions so that it isn't
neccessary to pass T as a template parameter to each of the policies.
Andrei's policies also supply types; these could be handled with nested type
generators if neccessary:
struct my_policies
{
...
template <class T>
struct traits
{
typedef T* StoredType; // the type of the pointee_ object
typedef T* PointerType; // type returned by operator->
typedef T& ReferenceType; // type returned by operator*
};
template <class SmartPointer>
typename SmartPointer::ReferenceType dereference(SmartPointer const& x)
{
// implementation of dereference behavior
}
};
We can supply orthogonal default policy components as follows, if desired:
struct empty {};
template <class MorePolicies = empty>
struct default_smart_ptr_storage : MorePolicies
{
...
};
template <class MorePolicies = empty>
struct default_smart_ptr_conversion : MorePolicies
{
...
};
So they can be chained together:
struct my_policies :
default_smart_ptr_storage<default_smart_ptr_conversion<> >
{
// my checking and ownership policy code here
// this allows as much interaction as desired
// between the checking and ownership aspects
};
But we can also provide:
struct default_smart_ptr_policies :
default_smart_ptr_storage<
default_smart_ptr_conversion<
default_smart_ptr_checking<
default_smart_ptr_ownership<> > > >
{
};
The Policy Adaptor pattern would encourage users to derive new policies from
default_smart_ptr_policies, replacing one element of the functionality at a
time. Typically, this approach is useful if a user is going to hand the
libarary one kind of "pointer" and request a variation on that pointer in
return (think of reverse_iterator or indirect_iterator for example).
Although it is not clear to me that this is a common need in the domain of
smart pointers (is it?), the concrete policy class may be useful for solving
the policy interaction problem.
One key difference I notice in Andrei's design is that the policies seem to
supply element's of the SmartPtr's public interface directly (e.g. op->()) .
It isn't clear to me whether this is essential or not; we should discuss it.
-Dave
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk