[fusion] Re: more help with unfused_typed (previously off-list)

Hello Christian, Christian Holmquist wrote:
Hello, I decided to mail you directly not to spam the boost dev-list with minor questions, hope it's ok.
Sure, but I think we're not spamming ;-). To the contrary, it's valuable to discuss this stuff on-list (forwarding to boost.devel -- hoping it's OK), because ...
My question is how to disable the call operators with fewer arguments than specified by Sequence, generated by unfused_typed<F, Sequence>. Before the switch to boost::result_of one could specialize the result struct to only handle the expected Sequence type, thus disabling unwanted operators. I'm not familiar with boost::result_of to describe this however.
... I removed that kind of control over the overload sets of the Fusion functional adapters (you can't pass emptiness through result_of), but I'm not really happy about it. <snip code>
Any ideas? Currently I think it might be best to re-add that mechanism for the 'unfused_*' adapters, either by checking nested 'result' of the target function for emptiness (exploiting SFINAE where applicable) or by introducing a special type (e.g. 'fusion::undefined_function'), that when returned from 'result_of' disables the overload...
Thoughts anyone? Regards, Tobias

To me it would be reasonable that unfused_typed, given its name, only generated the operator to create exactly the sequence type provided. I was surprised it didn't at first, but since it was clearly documented how to avoid this behaviour I didn't think too much about it. If this feature requires extra tweaks, wouldn't it be easier to avoid it? Is it some particular case you have in mind where one would want to to default-initialize parts of the sequence? Regards,
My question is how to disable the call operators with fewer arguments than specified by Sequence, generated by unfused_typed<F, Sequence>. Before the switch to boost::result_of one could specialize the result struct to only handle the expected Sequence type, thus disabling unwanted operators. I'm not familiar with boost::result_of to describe this however.
... I removed that kind of control over the overload sets of the Fusion functional adapters (you can't pass emptiness through result_of), but I'm not really happy about it.
<snip code>
Any ideas? Currently I think it might be best to re-add that mechanism for the 'unfused_*' adapters, either by checking nested 'result' of the target function for emptiness (exploiting SFINAE where applicable) or by introducing a special type (e.g. 'fusion::undefined_function'), that when returned from 'result_of' disables the overload...
Thoughts anyone?
Regards, Tobias

Christian Holmquist wrote:
To me it would be reasonable that unfused_typed, given its name, only generated the operator to create exactly the sequence type provided. I was surprised it didn't at first, but since it was clearly documented how to avoid this behaviour I didn't think too much about it. If this feature requires extra tweaks, wouldn't it be easier to avoid it?
That might be an interesting option for 'unfused_typed'. But the concern is not about a particular feature of 'unfused_type' -- error handling might have gotten worse for all 'unfused_*' adapters.
Is it some particular case you have in mind where one would want to to default-initialize parts of the sequence?
BTW: There is no default initialization of Sequence elements. If there are less arguments you get a shorter Sequence. Enabling the resulting function (object) to pose as a function with default arguments and allowing argument patterns (such as: (key, value, default)) were the reasons for making that adapter implicitly variadic. Also, all other 'unfused_*' adapters are inherently variadic (for which this property is pretty much self-evident). Regards, Tobias

That might be an interesting option for 'unfused_typed'. But the concern is not about a particular feature of 'unfused_type' -- error handling might have gotten worse for all 'unfused_*' adapters. Also, all other 'unfused_*' adapters are inherently variadic (for which this property is pretty much self-evident).
unfused_typed differs from the rest of the unfused_* adapters, since it's the only one not generating an arbitrary sequence (at least, this is the way I would prefer it to behave). Wouldn't it solve the problem by simply not create operators for anything except for the supplied Sequence in this case? Then any unary function object could have its result type calculated with result<Self(Sequence)>, regardless of which unfused_* adapter wrapping it. When using unfused_typed ATM I have to describe my Sequence twice, once for the adapter and once for my functor, only to gurantee no other sequence than expected is created. This doesn't seem right.
BTW: There is no default initialization of Sequence elements. If there are less arguments you get a shorter Sequence. Of course, don't know what I was thinking here (since this is _the_ reason I wrote you in the first place =)).
Regards,

On 7/17/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Christian Holmquist wrote:
My question is how to disable the call operators with fewer arguments than specified by Sequence, generated by unfused_typed<F, Sequence>. Before the switch to boost::result_of one could specialize the result struct to only handle the expected Sequence type, thus disabling unwanted operators. I'm not familiar with boost::result_of to describe this however.
... I removed that kind of control over the overload sets of the Fusion functional adapters (you can't pass emptiness through result_of), but I'm not really happy about it.
<snip code>
Any ideas? Currently I think it might be best to re-add that mechanism for the 'unfused_*' adapters, either by checking nested 'result' of the target function for emptiness (exploiting SFINAE where applicable) or by introducing a special type (e.g. 'fusion::undefined_function'), that when returned from 'result_of' disables the overload...
Thoughts anyone?
Sure... like Christian, initially I was expecting that unfused_typed would give me only the overload with all of the types, but then when I saw what it did it wasn't too hard to follow the instructions and disable all of the other overloads. Now that that mechanism is gone, the fusion::undefined_function seems like a replacement that would work. Let's see - in that case could you even do something like this, when result_of becomes a typeof-forwarder: // warning: not too well thought over code struct foo { template<typename Seq> typename enable_if<is_right_kind_of<Seq>, type>::type operator()... template<typename Seq> typename disable_if<is_right_kind_of<Seq>, fusion::undefined_function>::type operator()... }; and that way the user wouldn't need to know about result_of any more, right? Although, if there is a need for specifying that a function should not be called a certain way, maybe it should have a more generic treatment, like boost::undefined_function for starts? Just in case someone needs to tell both fusion and something else to stay away, for the same function object. Hmm... now that I think of it, I guess in something I was working on I implemented a "has_result_of" trait that checks for either existence of result_type, or the right result overload... that might also work here, but I'm not sure how my has_result_of implementation fares, and whether it can be fixed to use result_of directly (i tried and failed for some reason) and also work when result_of is a typeof forwarder. So I don't know about whether this might also be an avenue. Well, that's my thoughts :-) Thanks for asking. In my code I'm using something like a unfused_typed_inherited which inherits the unfused function (because I need it to have both the original fused operator and the unfused operator). I think I showed it to you at some point, although I got rid of that whole "unfusing the constructor as well" business. Anyway, in that one I only use the overload with all specified args, since that's all I need anyway. Cheers, Stjepan

On 7/17/07, Stjepan Rajko <stipe@asu.edu> wrote:
On 7/17/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Christian Holmquist wrote:
My question is how to disable the call operators with fewer arguments than specified by Sequence, generated by unfused_typed<F, Sequence>. Before the switch to boost::result_of one could specialize the result struct to only handle the expected Sequence type, thus disabling unwanted operators. I'm not familiar with boost::result_of to describe this however.
... I removed that kind of control over the overload sets of the Fusion functional adapters (you can't pass emptiness through result_of), but I'm not really happy about it.
Hmm... now that I think of it, I guess in something I was working on I implemented a "has_result_of" trait that checks for either existence of result_type, or the right result overload... that might also work here, but I'm not sure how my has_result_of implementation fares, and whether it can be fixed to use result_of directly (i tried and failed for some reason) and also work when result_of is a typeof forwarder. So I don't know about whether this might also be an avenue.
... I guess I called it "result_of_defined" - the code is at http://tinyurl.com/23xz6t if you have any feedback. Stjepan

Stjepan Rajko wrote:
On 7/17/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Christian Holmquist wrote:
My question is how to disable the call operators with fewer arguments than specified by Sequence, generated by unfused_typed<F, Sequence>. Before the switch to boost::result_of one could specialize the result struct to only handle the expected Sequence type, thus disabling unwanted operators. I'm not familiar with boost::result_of to describe this however. ... I removed that kind of control over the overload sets of the Fusion functional adapters (you can't pass emptiness through result_of), but I'm not really happy about it.
<snip code>
Any ideas? Currently I think it might be best to re-add that mechanism for the 'unfused_*' adapters, either by checking nested 'result' of the target function for emptiness (exploiting SFINAE where applicable) or by introducing a special type (e.g. 'fusion::undefined_function'), that when returned from 'result_of' disables the overload...
Thoughts anyone?
Sure... like Christian, initially I was expecting that unfused_typed would give me only the overload with all of the types
I think I'll just change 'unfused_typed' to these semantics (with two overloads - for const-correctness ;-) ). Hopefully those changes will also keep MSVC 7.1 from ICEing for the non-const operator() (see workaround in the code)... <snip>
Although, if there is a need for specifying that a function should not be called a certain way, maybe it should have a more generic treatment, like boost::undefined_function for starts? Just in case someone needs to tell both fusion and something else to stay away, for the same function object.
Hmm... now that I think of it, I guess in something I was working on I implemented a "has_result_of" trait that checks for either existence of result_type, or the right result overload... > that might also work here, but I'm not sure how my has_result_of implementation fares, and whether it can be fixed to use result_of directly (i tried and failed for some reason) and also work when result_of is a typeof forwarder. So I don't know about whether this might also be an avenue.
There is a consistent, intermediate state in the CVS (about a week ago), that uses the nested 'result' directly (with 'result_of' protocol) and checks for emptiness. I actually considered keeping this version, documenting another concept (refinement of Polymorphic Function Object requiring nested 'result' that can be empty), but concluded that this approach feels wrong, because it can't work with 'result_of', relies on result type computation (which can be removed with the next language version) and it complicates the conceptual perspective of things. Reading your code (link in the follow-up post) it seems you're checking for a similar (though not identical, because of 'result_type') concept.
Well, that's my thoughts :-) Thanks for asking. In my code I'm using something like a unfused_typed_inherited which inherits the unfused function (because I need it to have both the original fused operator and the unfused operator). I think I showed it to you at some point, although I got rid of
that whole "unfusing the constructor as well" business.
Yep, I remember. Such a "function template emulator" is actually quite tempting to have - I'll eventually get back to it. Regards, Tobias
participants (3)
-
Christian Holmquist
-
Stjepan Rajko
-
Tobias Schwinger