Re: [Implementation] Calling wrapped functions, converters, policies

David Abrahams <[email protected]>
Newsgroups gmane.comp.lib.boost.langbinding
Message-ID <[email protected]>
Daniel Wallin <[email protected]> writes:


>>>IIRC this is close to what you have in boost python today.
>
>> Yep, close.  It's missing the "hidden this downcasting" feature,
>> which we'll need.
>
> Right,
>
>    template<class R, class T, ..., class WrappedClass>
>    signature<
>        mpl::vector3<WrappedClass&, R, ...>

What does the first element of the vector mean?  Oh, looking back at
your previous message that's a *very* strange ordering!  Why would you
put the return type *second*?!


>        ...
>    >
>    signature_of(R(T::*)(...), type<WrappedClass>)
>
> ?

I'm not sure whether what you're suggesting above actually does the
right thing.  In fact, I'm almost certain it doesn't.  You need the
most_derived hook used in signature.hpp.  The idea is, "downcast if
you can, otherwise leave it alone".

BTW, I like using a WrappedClass* instead of type<WrappedClass> because I
think it costs fewer compilation resources.

>>>   - A CallPolicies concept which is a binary metafunction class that can
>>>     generate a converter for a type T and argument index N.
>> That sounds like a from-XXX converter generator, but not the full
>> concept that is CallPolicies in my mind, which includes converting
>> results to-XXX.
>
> Right.. I don't remember exactly what we decided on this, if we ever did
> decide anything. When I wrote this I was thinking that
> CallPolicies::apply generates a converter that can convert the type in
> both directions, and the direction is decided later by calling the right
> member function:
>
>     cv.to(...); // converts to XXX
>     cv.from(...); // converts from XXX
>
> Then we'd actually only have the ConverterGenerator concept, which
> CallPolicies models.

I have no problem in principle (I think) with bidirectional
converter *generators*, but bidirectional converters won't work.  They
need completely different data members, and from-XXX converters need
to be 2-phase for overloading, while to-XXX converters are one
phase.  In other words, I have no problem with:

        some_generator
        {
            template <class T>
            struct to
            {
                typedef ... type;
            };

            template <class T>
            struct from
            {
                typedef ... type;
            };
        };

> Did I miss anything, do we need to separate it into two concepts?

I hope I answered.

>>>   - generate_converter_tuple<Signature, CallPolicies>
>>>     Combines a given signature<> with a CallPolicies type and produces a
>>>     tuple type with converters that can perform the given conversion.
>>>
>>>and..
>>>
>>>   - A sample composite_call_policies<Seq> type that creates the
>>>     equivalent of map<Index, CallPolicy>. 
>> Do you really need random access over non-contiguous indices?
>> That's
>> what map<Index, ...> implies to me.
>
> To clarify, this models what we have in luabind.
>
>    policy1(_2) + policy2(_1)
>
> Would create something like:
>
>    composite_call_policies<
>        mpl::vector<
>            node<mpl::int_<2>, policy1_type>
>          , node<mpl::int_<1>, policy1_type>
--------------------------------------^
>        >
>     >

Really??  Just so as not to confuse things, I suggest policyA and
policyB.  So:

     policyA(_2) + policyB(_1)

  Would create something like:

     composite_call_policies<
         mpl::vector<
             node<mpl::int_<2>, policyA_type>
           , node<mpl::int_<1>, policyB_type>
         >
      >

??
> And it's nested apply<> would do something like:
>
>    apply(Type, Index)
>       if we have a child, C,  that matches node<Index, _>
>           C::apply(Type, Index)
>        else
>           default_call_policies::apply(Type, Index)

It looks to me like the Children model a different concept from the
composite, in that they're index-agnostic (or should be).  The
children are converter generators, aren't they?  Didn't we make a
bunch of these decisions about naming already?

> The indices here are generally non-contiguous, since the user rarely
> would specify an explicit policy for each argument index.

Why not use an mpl::map or mpl::multimap?

Yes, you or Aleksey will have to implement it.  But I'm sure he'd
be happy to oblige.   ;->


>>>     It also combines it's childrens argument_package types and
>>>     state types by inheritance.
>> Not sure what you mean by "by inheritance".
>
> It means it's nested state_type inherits from all it's "childrens"
> state_types.

I guess states have to be classes then?  I think there's a way to lift
this restriction using an explicit get function and inheritance from
wrappers:

     template <class Head, class Tail>
     struct cons : Tail
     {
         Head h;
     };

     template <class Head, class Tail>
     Head& get(cons<Head,Tail>& x) { return x.h; }

Now each state type (the "head" of a cons sub-list) can be whatever
you like.

> Again,
>
>    composite_call_policies<
>        mpl::vector<
>            node<mpl::int_<2>, policy1_type>
>          , node<mpl::int_<1>, policy1_type>
>        >
>     >
>
> Would make something like:
>
>     template<class Base, class CallPolicies>
>     struct inherit_state : Base, CallPolicies
>     {
>         template<class U>
>         inherit_state(const U& init)
>             : Base(init), CallPolicies(init)
>         {}
>     };
>
>     typedef typename inherit_linearly<
>         PoliciesSequence
>       , empty
>       , inherit_state<_1, _2>
>     >::type
>
> Except that it's a bit more complicated; every state type is only
> inherited once.

mpl::set, anyone?

> The same goes for argument_package. Here we also have get() functions:
>
>     template<class Base, int N>
>     PyObject* get(PyObject* args, mpl::int_<N>)
>     { return PySomethingSomething(.., N); }
>
>     template<int N>
>     struct offset_arg // IIRC you have something like this in BPL
>     {
>         offset_arg(PyObject*) {}
>     };

Yep, in boost/python/make_constructor.hpp

> With a special overload that handles the composite case where every
> argument_package has a base type which must be queried:
>
>     template<class Base, int M, int N>
>     PyObject* get(offset_arg<M>, const Base& base, mpl::int_<N>)
>     { return get(base, mpl::int_<N + M>()); }

Wha??

Why isn't the base object stored in the offset_arg<>, as in BPL?  Do
you need to explain what Base is?

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com



-------------------------------------------------------
This SF. Net email is sponsored by: GoToMyPC
GoToMyPC is the fast, easy and secure way to access your computer from
any Web browser or wireless device. Click here to Try it Free!
https://www.gotomypc.com/tr/OSDN/AW/Q4_2003/t/g22lp?Target=mm/g22lp.tmpl
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.