Re: Re: [Implementation] Calling wrapped functions, converters, policies
Daniel Wallin <[email protected]>
| Newsgroups | gmane.comp.lib.boost.langbinding |
|---|---|
| Message-ID | <[email protected]> |
David Abrahams wrote: > 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*?! 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. :) >> ... >> > >> 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". 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? > BTW, I like using a WrappedClass* instead of type<WrappedClass> because I > think it costs fewer compilation resources. Ok good point. >>>> - 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: > > [snip] OK agreed. So, should the nested member be a metafunction class? some_generator { typedef /* to converter */ to; typedef /* from converter */ from; }; And how does this fit in with how the converter_tuple is generated? Shouldn't all converters be in the tuple, regardless of in what direction they should convert? How could the converter_tuple_generator know which types should be "to" and which should be "from"? My version just iterates over all types and generates a converter for every one, not knowing anything about directions. >>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?? No, of course I mistyped. Should have choose better names. :) > 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> > > > > > > ?? Exactly. >>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? 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. > Didn't we make a bunch of these decisions about naming already? Yeah we did. I think we said that there are basically two concepts, ConverterGenerator and CallPolicies. CallPolicies is a refined ConverterGenerator which has precall/postcall actions. I'm going to browse through the archives after I post this, if I was wrong I'll repost. :) >>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? That's fine by me. > Yes, you or Aleksey will have to implement it. But I'm sure he'd > be happy to oblige. ;-> Didn't you already implement an associative mpl container? IIRC I have seen you talk about it in some posts. I did it once for fun, except it wasn't really a map but sort of a container adaptor. // BaseContainer := mpl sequence of mpl::pair<Key, Value> template<class BaseContainer> struct map_adaptor; That was pretty far from mpl standard though, so lets wait for Aleksey. :) >>>> 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. And extract the state type by explicitly supplying Head? get<my_state_type>(state); It isn't as nice as implicit conversion, but I guess it'll work. I don't know though; do states really need to be non-class types? Sure, I can see why someone could find the need for it, but if you don't wrap your type in a class, there's always a risk for collisions with other policies in a composite. Two policies can use "int" for completely different things, and we can't discriminate them. >>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? Sure. Now I'm doing something like: template<bool B, class Base, class CallPolicies> struct inherit_state_aux : Base, CallPolicies::state_type {}; template<class Base, class CallPolicies> struct inherit_state_aux<true, Base, CallPolicies> : Base {}; template<class Base, class CallPolicies> struct inherit_state : inherit_state_aux< is_convertible< Base*, typename CallPolicies::state_type>::value >::value , Base , CallPolicies > { ... }; typedef typename inherit_linearly< PoliciesSequence , empty , inherit_state<_1, _2> >::type Except I'm not using partial specialization.. Whether or not we are using mpl::set or this doesn't matter to me. My guess is that my version would compile faster, but obviously is less clear. I could be wrong though. >>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? Because the different CallPolicies in the composite_call_policies type have no knowledge of each other. Meaning we would need to make the nested argument_package a metafunction: struct my_policy { template<class Base> struct argument_package { typedef offset_arg<1, Base> type; }; }; I think it's nicer to create a composite hierarchy: composite_argument_package< offset_arg<1> , composite_argument_package< offset_arg<9> , composite_argument_package_native< PyObject* > > > template<class Pkg, class Base> struct composite_argument_package : Base { // some forwarding constructors goes here Pkg pkg_; }; template<class Pkg, class Base, int N> PyObject* get( const composite_argument_package<Pkg, Base>& x, mpl::int_<N>) { // forward to correct get() function return get(x.pkg_, static_cast<const Base&>(x), mpl::int_<N>()); } See what I'm driving at? 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". -- Daniel Wallin ------------------------------------------------------- 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