Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-10-08 18:05:24


Ok, I did something very cool with MPL that is also apparently incorrect,
judging by the test results. Here's the most relevant portions, and some
explanation:

    template <class F, typename T>
    struct apply_lambda
    {
        typedef typename mpl::lambda<F>::type f_;
        typedef typename mpl::apply<f_, T>::type type;
    };

    // Extracts the policy_category as a metafunction
    template <class Policy>
    struct get_category
    {
        typedef typename Policy::policy_category type;
    };

    // Avoids premature dereferencing so as to properly handle the end
    // iterator
    template <typename T>
    struct make_iterator
    {
        typedef T type;
    };

    template <class Sequence, class Category, class Default>
    struct get_policy
    {
        typedef typename mpl::find_if<
            Sequence, is_same<get_category<_>, Category>
>::type i_;
        typedef typename mpl::if_c<
            ::boost::is_same<i_, mpl::end<Sequence>::type >::value,
            make_iterator<Default>, i_
>::type::type type;
    };

# define BOOST_STORAGE_POLICY
\
    apply_lambda<
\
        get_policy<policies_, storage_policy_tag, scalar_storage<_> >::type,
\
        T
\
>::type
# define BOOST_CHECKING_POLICY
\
    apply_lambda<
\
        get_policy<policies_, checking_policy_tag, assert_check<_> >::type,
\
        typename BOOST_STORAGE_POLICY::stored_type
\
>::type
# define BOOST_OWNERSHIP_POLICY
\
    apply_lambda<
\
        get_policy<policies_, ownership_policy_tag, ref_counted<_> >::type,
\
        typename BOOST_STORAGE_POLICY::pointer_type
\
>::type
# define BOOST_CONVERSION_POLICY
\
    apply_lambda<
\
        get_policy<policies_, conversion_policy_tag, disallow_conversion<_>
>::type, \
        typename BOOST_STORAGE_POLICY::pointer_type
\
>::type

    struct empty_policy
    { typedef void policy_category; };

    template <
        typename T,
        class P1 = empty_policy, class P2 = empty_policy,
        class P3 = empty_policy, class P4 = empty_policy,
        class policies_ = mpl::list<P1, P2, P3, P4>
>
    class smart_ptr
        : public optimally_inherit<
            optimally_inherit<
                BOOST_STORAGE_POLICY,
                BOOST_OWNERSHIP_POLICY
>::type,
            optimally_inherit<
                BOOST_CHECKING_POLICY,
                BOOST_CONVERSION_POLICY
>::type
>::type
    {
    public: // Policy types
        typedef T element_type;
        typedef BOOST_STORAGE_POLICY storage_policy;
        typedef BOOST_OWNERSHIP_POLICY
ownership_policy;
        typedef BOOST_CHECKING_POLICY checking_policy;
        typedef BOOST_CONVERSION_POLICY
conversion_policy;
        typedef typename optimally_inherit<
            optimally_inherit<
                BOOST_STORAGE_POLICY,
                BOOST_OWNERSHIP_POLICY
>::type,
            optimally_inherit<
                BOOST_CHECKING_POLICY,
                BOOST_CONVERSION_POLICY
>::type
>::type base_type;
        typedef typename base_type::base1_type::base1_type storage_base;
        typedef typename base_type::base1_type::base2_type ownership_base;
        typedef typename base_type::base2_type::base1_type checking_base;
        typedef typename base_type::base2_type::base2_type conversion_base;
        typedef smart_ptr this_type;
    };

Now, in case you haven't guessed, the intention of this code is to allow
arbitrary ordering of policies(!). And it looks like it works. Well, it
compiles,
anyway, on gcc 3. However, one of my tests fails, and it's probably
because it's calling the wrong constructor. With all the c'tors in the
library,
this is not suprising. Getting the right ones called is quite a trick.
However,
it's nearly impossible for me to debug this code, because single compile
errors tend to be ten pages long, and completely inscrutable. And I have
no idea what type actually filters down into the class, even though it
appears
that whatever types they are, they work correctly.

First, I would like a sanity check. Did I write the metafunctions
correctly?
Did I call them correctly? Am I overlooking any minor mistakes that could
be causing my problem? Is there any way to simplify the code further?
It would be nice to combine the get_policy<> and apply_lambda<>
functions somehow, but I couldn't think of an elegant way to do it.

Second, what do you expect to be the type of the policies after getting
cranked through the policy adaptor? Do they have some funky type, or
do they manage to get passed through more or less unchanged? It seems
that they can't be getting changed too much, or all the code would break.
On the other hand, there must be just enough mess to confuse the overload
resolution system.

It's quite nice that my test code can do this:

        boost::smart_ptr<
            object,
            boost::ref_counted<_>,
            boost::assert_check<_>
> p(new object(dead));

        boost::smart_ptr<
            object,
            boost::scalar_storage<_>,
            boost::disallow_conversion<_>
> q(p);

I just wish it also did the right thing at run-time! :( BTW, MPL is *very*
cool! I don't know if multiple sequence types are good or bad, but I do
know that the meta-iterator paradigm made it within my grasp to
actually write this code (which I'm almost certain *I* could not do using
raw dot-lists).

Dave


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