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:

> David Abrahams wrote:
>
>> [Aleksey, please see below w.r.t. lambda exprs]
>> Daniel Wallin <[email protected]> writes:
>> 
>>>David Abrahams wrote:
>>>
>>>>Daniel Wallin <[email protected]> writes:
>>>>
>>>>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*?!
>>>
>>>The ordering was arbitrary. Well, sort of at least. The reason was to
>>>keep the indexing consistent. A member function signature is the same as
>>>a function signature, except it has the self-type at index 0. So the
>>>index to some type in the signature is just offset one step. I don't
>>>know if it matters though. :)
>> Errf.  I think of these two as equivalent:
>>        A f(B*, C, D, E)
>>        A B::f(C, D, E)
>> And they *are* equivalent as far as Boost.Python is concerned,
>> except
>> at the last second when the C++ function is invoked and we have to do
>> some syntactic adjustment to account for the difference between
>> member and non-member functions.  I don't see any reason to drag the
>> B* to the beginning of the signature.
>
> Good point.
>
>>>>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".
>>>
>>>I had a look in signature.hpp. I'm not sure I understand this though;
>>>Target is not more derived than T => Target == T, no? Or is Target
>>>something else than the current WrappedClass type?
>> Well, this should probably be done for non-member functions as well,
>> but...
>> suppose someone does this:
>> [snip code]
>> That should show why the most_derived thing is there.
>
> OK, I had no idea you could do that. I can see why you would need
> most_derived there. I'm not sure I can see why anyone would do
> something like that though, but I haven't given it much thought. :)

Run the following:

  #include <typeinfo>
  #include <stdio.h>
  struct B { void f() {} };
  struct D : B {};
  int main()
  {
      printf(typeid(&D::f).name());
      return 0;
  }


"Like what?"  Did you mean, why anyone would want to use a member
function on some non-base class as a staticmethod?

It doesn't really matter; they could be free functions:

        struct Base  // not wrapped
        {
        };
        void f(Base*);

        struct Baz // wrapped
        {
        };
        void g(Baz*);

        struct Derived : Base // wrapped
        {};


   class_<Derived>("Derived")
       .def("f", &Base::f)
       .def("g", &Baz::g)
       .staticmethod("g")
       ;

   >>> d = Derived()
   >>> d.f()
   >>> d.g(Baz())


>>>>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:
>>>>[snip]
>>>
>>>OK agreed. So, should the nested member be a metafunction class?
>>>
>>>   some_generator
>>>   {
>>>       typedef /* to converter */ to;
>>>       typedef /* from converter */ from;
>>>   };
>> Well, it can be more efficient than using any generalized lambda
>> expr,
>> but it's also more work for the user.  AFAIK MPL is going to change so
>> that apply<...> uses lambda<...> internally, but I guess there would
>> always be a lower-level apply_metafunction_class<...> for efficiency.
>> Even though we've written about that in our book, it's not implemented
>> yet.  Aleksey, care to comment?
>
> OK. How would you apply<> to a nested metafunction? By turning them into
> lambda-types? 

Yep.

> Or is it safe (portable) to do
>
>    typedef typename generator::template to<T, Index>::type cv_t;
>
> I know I've had a lot of problems with that syntax on VC before.

Yep, not very portable.  That's why to use apply<...>.

>>>How could the converter_tuple_generator know which types should be
>>> "to" and which should be "from"? 
>> If you use a consistent signature ordering as I'm suggesting, it's
>> easy.  To for the first and from for the rest.
>
> Yeah, that would work fine. But I'm not sure I like it. How does it
> apply to explicit conversions? (object_cast<> / extract<>). I had
> thought that we'd handle these cases by just supplying a vector1<T>
> signature sequence.. 

    vector2<T,object>  // from-XXX

or 

    vector2<object,T>  // to-XXX

Simple ;-)

> But we could tell the policy to generate the converter explicitly
> instead of using generate_converter_tuple<>.. I'm not sure what I
> think about this.

Not sure what you're driving at here.

>>>No I think the children are CallPolicies as well - they should have
>>>precall/postcall actions.
>>>
>>>I'm not sure what you mean by index-agnostic.
>>
>> I think I'm just forgetting stuff you already convinced me of, but
>> what I meant was that the others are only really concerned with
>> converting a single argument and so don't need an index, while the
>> CallPolicies are concerned with the whole argument tuple.  But I
>> think we agreed they all need the index.
>
> Yeah I think we did. I guess most of "the others" will likely just
> ignore the index though, provided that the index is passed to the
> converter later.
>
>     struct my_cv;
>     my_cv cv;
>     cv.from(..., mpl::int<2>());
>
> vs
>
>     template<int N>
>     struct my_cv;
>     my_cv<2> cv;
>     cv.from(...);

Do we want to pass the index into the converter later?  I don't think
we do.  Seems to me that you might want some converters to,
ultimately, work on several indices.  Maybe I'm wrong.

>>>BTW, if you implement the composite CallPolicies like you have in BPL
>>>there is no reason why offset_arg couldn't store it's Base. That's of
>>>course a perfectly fine model of CallPolicies as well.
>>>composite_call_policies is just an example of how it can be done without
>>>explicit inheritance from your "Base policy".
>> I think you can also get there by having the names that the user
>> handles
>>     some_policyA(_1)
>>     ^^^^^^^^^^^^
>> refer to instances of some concept other than CallPolicies which can
>> generate CallPolicies.  Not sure what's best yet.
>
> I think it's best to allow both approaches.

It strikes me that the user isn't handling call policy names anyway,
because,

1. In "policyA(_1)", policyA can't be type name.
2. policyA(_1) and policyA(_2) have to generate different types.

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