Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2002-04-30 23:30:19


From: "David B. Held" <dheld_at_[hidden]>

> "David Abrahams" <david.abrahams_at_[hidden]> wrote in message
> > From: "David B. Held" <dheld_at_[hidden]>
> > > Vertical policies facilitate IPC, but at a cost, depending on the
> > > architecture. For instance, Beman made a tradeoff between
straight
> > > vertical and straight horizontal policy design (diagonal
policies?).
> > > On the one hand, it simplified the design. On the other hand, it
fixed
> > > which policies could see each other.
> >
> > It doesn't have to. You /can/ leave the ordering up to the user. I
have
> > in mind a "construction kit" where you configure new smart pointers
like
> > this:
>
> I must be dense, because I don't see how this is at all similar to
Beman's
> design, in which the Storage policy appears intended to derive from
> both Checking and Conversion.

Don't see why that makes you dense. I never claimed it was like Beman's
design.

> The fact that it contained MI, but was
> also chained is why I called it a "diagonal" design. It looks like
what
> you're suggesting is yet another class of designs that I might call a
> "ring".
>
> > template <class Value, class Ptr = Value*>
> > struct my_ptr
> > : smart_ptr<
> > com_refcounted<
> > always_non_null<
> > my_ptr<Value,Ptr> > > >
> > {};
> >
> > Incidentally, this basic approach was suggested to me by Mat Marcus
> > at the C++ committee meeting; according to him it's straight GenVoca
> > out of C&E.
>
> It looks pretty interesting. I still have a hard time getting my head
> around
> the idea of something inheriting from itself.

Nothing can do that in C++. This is just the straightforward "curiously
recursive template" pattern, as employed (for example) by the operators
library.

> However, I can see how
> this would be pretty flexible, avoids a template template policy
param,
> eliminates an explicit pointee type param (in the policies and the
> smart_ptr type), and gives all the policies access to the base types,
all
> in one fell swoop. Of course, it never would have occurred to me that
> deriving from a smart pointer type instead of instantiating it would
yield
> such benefits; but I guess it's just another example of solving a
problem
> by adding a layer of indirection, eh? I suppose I should check out
C&E.

Perhaps so.

> > > The cost I noticed in vertical chaining is the presence of
> > > constructors. All policies in the chain must provide the same
> > > set of c'tor signatures.
> >
> > Not neccessarily, but I can see how it would work out best that way.
>
> Oh. Just out of curiosity, how could you avoid that, without changing
> the design dramatically?

If there were base policies which didn't need access to the pointer,
they could have a default constructor. Maybe the policies don't hold the
pointer at all, but get passed the entire smart_ptr<> object for each
operation and extract the pointer explicitly.

> In mine as well, unless smart_ptr were made to work with, say,
> shared_ptr, and you started adding all these conversion c'tors
> that started cluttering up the policies considerably.

You don't put those in the policies. They just live in the outer class.
Hmm, conversion poses an interface-reuse problem with the above
arrangement. In that case, either smart_ptr<> is your outermost class or
you add forwarding constructor/assignment to my_ptr.

> > "Of course?" Please back up a few steps and explain for those
> > of us who are less sophic.
>
> I didn't mean to sound like a sophist

Sophic == WISE discerning, gnostic, insighted, insightful, knowing,
knowledgeable, perceptive, sagacious, sage
according to my thesaurus.

> , but instead of backing up, I
> do believe I explained this statement in the following paragraph.
> Basically, if your policies can "arrive" in any order, then you can't
> just assign default policies to each template parameter, like so:
>
> template <
> class Policy1 = default_policy_A,
> class Policy2 = default_policy_B,
> class Policy3 = default_policy_C,
> class Policy4 = default_policy_D
> >
> class policy_based_class
> : public Policy1<Policy2<Policy3<Policy4> > > >
> { };
>
> Obviously, if I provide a C and D policy, and nothing else, I end
> up with two C and two D policies, and no A and B policies.

Yep.

> > I'm not sure I see this. The approach I have in mind is actually a
> > Policy Adapter pattern: the default policy is to dispatch to the
> > behavior of the underlying Ptr type.
>
> I'm afraid I don't grok this at all. If you're talking about the
> iterator adaptors Policy Adaptor, then I kinda know what you
> mean.

That's what I mean.

> I read what appeared to be the relevant parts of the iterator
> adaptors paper, as well as browsed the source code. All of it
> mostly made my head swim. :( I see references to "named
> template parameters", which I thought were totally different
> from a policy adaptor,

They are. That's just a technique used to provide a nice interface.

> but when I looked at the implementation,
> I saw how you searched through the policy list, which is more
> or less what I expected. I guess I never understood how named
> template parameters were implemented. Have you considered
> rewriting it with MPL (after it's reviewed, of course)? Or would
> that be a bad dependency?

Not neccessarily bad.

> It seems to me that a policy adaptor is a fairly generic idea.
> Have you considered generalizing it, and making it standalone,
> so other policy-based designs can take advantage of it?

It's already as general as it can get: it's a design pattern. Anything
can take advantage of it. Trying to write a generalized policy adaptor
in code could only make it less general.

-Dave


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