Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-05-01 23:42:15


"David Abrahams" <david.abrahams_at_[hidden]> wrote in message
news:07a601c1f0c9$09d3c210$6401a8c0_at_boostconsulting.com...
>
> 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
>
> Don't see why that makes you dense. I never claimed it was like
> Beman's design.

I misread you as saying that with Beman's design, you can leave the
ordering up to the user. I see that you were simply saying that with
full vertical policy chaining, you can have any order. I assumed that
was one of the reasons one would choose vertical chaining.

> > [...]
> > 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++.

Well, not directly. ;)

> This is just the straightforward "curiously recursive template" pattern,
> as employed (for example) by the operators library.

Whenever I see people mention it, they seem to call it the "curiously
recurring template pattern", from which I gathered that it pops up in
unusual circumstances. But I can see that "recurrent" is also a
mathematical term for "recursive", and so the term is a bit
ambiguous. When you pointed out that it's a *recursive* pattern,
it all made sense. I don't even want to think about what a compiler
has to do to make that work. :(

> [...]
> 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.

Ok. But when you delegate storage to a policy (a la Loki::SmartPtr),
it seems that you have to have extra c'tors in every policy, right?

> > 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.

I see. I was confused by the fact that you pass a raw pointer to
policy classes. But with a conversion c'tor, you could just take out
the raw pointer, and pass that down.

> [...]
> > 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.

True. But writing anything in code makes it less general. ;) However,
it seems to me that MPL lets us write something fairly cool. I.e.:

    namespace detail
    {
        class no_policy_tag;

        template <typename T>
        class no_policy
        {
            typedef no_policy_tag policy_tag;
        };

        class no_defaults
        {
            typedef no_policy_tag default_tag_1;
            typedef no_policy_tag default_tag_2;
            typedef no_policy_tag default_tag_3;
            typedef no_policy_tag default_tag_4;

            template <class>
            class default_policy_1;
            template <class>
            class default_policy_2;
            template <class>
            class default_policy_3;
            template <class>
            class default_policy_4;
        };
    } // namespace detail

    template
    <
        template <class> class Policy1 = detail::no_policy,
        template <class> class Policy2 = detail::no_policy,
        template <class> class Policy3 = detail::no_policy,
        template <class> class Policy4 = detail::no_policy,
        template <class> class Defaults = detail::no_defaults
>
    class policy_adaptor
    {
        // MPL pseudo-code
        mpl::typelist policies<Policy1, Policy2, Policy3, Policy4>;

        typedef typename mpl::find_if<policies,
            is_same<
                typename _1::policy_tag,
                typename Defaults::default_tag_1
>::type
>::type iter1;
        typedef typename ct_if<
            is_same<iter1, mpl::end<policies>::type>,
            typename Defaults::default_policy_1, Policy1
>::type policy_1;

        typedef typename mpl::find_if<policies,
            is_same<
                typename _1::policy_tag,
                typename Defaults::default_tag_2
>::type
>::type iter2;
        typedef typename ct_if<
            is_same<iter2, mpl::end<policies>::type>,
            typename Defaults::default_policy_2, Policy2
>::type policy_2;

        typedef typename mpl::find_if<policies,
            is_same<
                typename _1::policy_tag,
                typename Defaults::default_tag_3
>::type
>::type iter3;
        typedef typename ct_if<
            is_same<iter3, mpl::end<policies>::type>,
            typename Defaults::default_policy_3, Policy3
>::type policy_3;

        typedef typename mpl::find_if<policies,
            is_same<
                typename _1::policy_tag,
                typename Defaults::default_tag_4
>::type
>::type iter4;
        typedef typename ct_if<
            is_same<iter4, mpl::end<policies>::type>,
            typename Defaults::default_policy_4, Policy4
>::type policy_4;

    public:
        template <typename T>
        class vertical
            : public policy_4<policy_3<policy_2<policy_1<T> > > > >
        { };

        template <typename T>
        class lateral
            : public policy_1<T>
            , public policy_2<T>
            , public policy_3<T>
            , public policy_4<T>
        { };

        template <typename T>
        class opt_lateral
            : public OptionalInherit<
                OptionalInherit<policy_1<T>, policy_2<T> >,
                OptionalInherit<policy_3<T>, policy_4<T> >,
>
        { };
    }

Usage:

So this doesn't preserve the order of policy specification, but I'm
sure that could be accomodated if necessary. And clearly, boost::
preprocessor could be used to scale it. Surely it's not as general
as the Policy Adaptor concept; but if it fits a wide range of uses,
then it has to be as useful as any other library, no?


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