Re: [C++-sig] [Implementation] Calling wrapped functions, converters, policies
David Abrahams <[email protected]>
| Newsgroups | gmane.comp.lib.boost.langbinding |
|---|---|
| Message-ID | <[email protected]> |
I think we need to stop using the term "policy" without qualification. It gets too confusing. Every time I do it, I mean CallPolicy (as in Boost.Python). I think when you do it you mean ConversionPolicy. In fact, why don't we say "[argument|result] [to|from]_xxx converter generator" for what I called ConversionPolicy? Daniel Wallin <[email protected]> writes: > At 14:09 2003-09-17, David Abrahams wrote: >>Daniel Wallin <[email protected]> writes: >> >> >> > struct ContextConcept >> >> > { >> >> > ... >> >> > something postcall(something_else); >> >> > }; >> >> > >> >> > struct ConverterConcept >> >> > { >> >> > ... >> >> > T convert(PolicyConcept::context_type& context); >> >> > }; >> >> >> >>This is passing the per-call state into the convert function? The >> >>problem I have with this is that the dynamically-registered converter >> >>implementation doesn't have access to the policy's static type, nor >> >>presumably to its nested context_type. >> > >> > Yes it does; the dynamically-registered converters are implemented as >> > a default policy >> >>You're not making sense here. The dynamic from-XXX converter >>implementation does not model the CallPolicy concept, nor, I think, >>the ConversionPolicy concept. > > The functions that does the actual conversion isn't, but the code that > looks them up and calls them is a model of ConversionPolicy. Of course. But it's the function which does the actual conversion which needs access to the state (or not, depending on the dynamically-selected converter). >>It basically comes down to one or two function pointers with a fixed >>static type for any given C++ target type. These function pointers >>get plugged into the static converter at runtime. > > Yeah, but they are called from a converter type. Like Boost.Pythons > rvalue_from_python, pointer_cref_from_python etc.. Sure, but what can that thing do with state, except in the case where there is no dynamic converter lookup at all? Not much. Maybe that's the way you see it? The default from_xxx converter generator builds a static converter which uses dynamic lookup and uses a default kind of state (say, a postcall chain) which is known to all the dynamically-registered converters, and the others use a kind of state which is determined at compile time by the static type of the converter (say, nested in the converter). >> > which selects the appropriate converter type. There >> > is no reason the system cannot be aware of the state type: >> > >> > struct default_state >> > { >> > postcall_chain* chain; >> > }; >> > >> > template<class T> >> > struct rvalue_converter >> > { >> > T& convert(default_state& state, ...) >> > }; >> >>If it's always a postcall chain, what's the point of nesting its type >>in the CallPolicy? > > My point was that it isn't always the postcall chain, it is in the case of > the default policy though. It isn't a postcall chain in the case of the > PyUnicode you mentioned earlier. Actually it could be handled that way... but I suppose that would be wasteful. As a matter of fact I think many static from_xxx converter types will want to wrap the default converter with additional behavior, so their state will need to include the postcall chain anyway. > Anyway, we don't need to nest it. It could just be a copy of the policy > object. > > What I'm driving at is that we don't need to make the whole postcall chain > thing into a special case, it can just as well be handled by the policy system "Policy system" is getting to be way too-fuzzy a term for me. But, yeah, I'm all for not having it be a special case. >> > Note that this is quite possible even if the policy object is copied and >> > used as state: >> > >> > struct default_policy >> > { >> > postcall_chain* chain; >> > void postcall(...) { for (postcall_chain* c = chain; c != 0; c = c >> > ->next) (*c)(..); >> > }; >> > >> >>Ya lost me here. > > Ok, I'll try to describe my vision of this. > > We have two concepts, CallPolicy and ConverterPolicy. We hold these policies > for each wrapped function object, in some type of list. Hum. By the time the function is wrapped, there's no need for argument from_xxx converter *generators* ("ConverterPolicies") anymore. At that point I think we just want a list of argument from_xxx converters. But since TMP is functional, it's really moot whether the determination of the actual converter is early or late. > It is possible to ask for the ConverterPolicy that can generate a > converter for a type in the signature at index N. > > ConverterPolicy is also a model of CallPolicy Noooooo! At least, not the way I understand it. CallPolicy is the Boost.Python concept that includes pre- and post-processing of the native interpreter argument tuple. > with the additional nested template type 'apply' which generates a > converter type. In that case, what's the concept you have been calling "CallPolicy?" > with the signature void f(T0, T1) and Policies we would wind up with > something like: > > Make copy of policy objects > > Call precall on each of the copied policy objects. > > Fetch converter policy type for index 0. > Create converter for index 0. What's the point of copying the policies in this scheme? Why not just store the state in the converter itself? > Fetch converter policy type for index 1. > Create converter for index 1. > > call ConverterN.match(...), if it fails overload > resolution fails. > > f(Converter0.convert(CopiedPolicyObject0), > Converter1.convert(CopiedPolicyObject1)); > > Call postcall on each of the copied policy objects. > > ----- And sample C++ code.. > > // the copied policy object, same policy for T0 and T1 > // so it's just one policy > default_policy policy0; Just one?! Wow, I'm really confused about that. What if they each need their own state? > policy0.precall(...); ^^^ What gets passed here? > // create converters > typename default_policy::apply<T0>::type c0; > typename default_policy::apply<T1>::type c1; > > int match_value = 0; > > match_value += c0.match(...); > match_value += c1.match(...); > > // do some magic with the match value to choose "best" overload > > f(c0.convert(policy0, ...), c1.convert(policy0, ...)); > > policy0.postcall(...); > > I'm having a really hard time getting my message across here. :/ I think we're having a problem with terminology. -- Dave Abrahams Boost Consulting www.boost-consulting.com ------------------------------------------------------- This sf.net email is sponsored by:ThinkGeek Welcome to geek heaven. http://thinkgeek.com/sf