as_sequence<R(T0,T1)> ?

I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1> -- Alexander Nasonov

Alexander Nasonov wrote:
I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1>
as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1>
as_sequence<R(T0,T1)> reads great, but this would add a lot to the complexity of 'as_sequence': First we have to idenitify if T is some sort of function (ptr/ref) type. Although there are ways to detect (not decompose, that is) functions and even member function pointers without using an unrolled cascades of specializations for different function arities, it requires a very standard compliant compiler. As we need to decompose the type and wrap its components into a vector in case it turns out to be a function anyway, we will instantiate one of these (more than 100) specializations. Note that in order to do all this a big chunk of code needs to be included and processed (the unrolled cascade of specializations to identify/decompose the function type and the cascade of 'mpl::vector' up to the maximum arity supported). This can significantly slow down the compilation time of a project (especially when separated into a lot of small translation units or when 'as_sequence' is used often). It may not be a good idea to impose these disadvantages on a "mostly harmless" user, probably not wanting to use this feature at all ;+). However there is a possiblility to give control to the user: As template specializations "slip through" to the namespace using them, a "dumb stub" could be added to 'as_sequence', never reporting that a type is a function. It could be "filled with life" afterwards when the user includes another header to enable 'as_sequence' for function types. Still I am not too sure this is a good idea. Comments about interest in this would be very helpful ! While we're at it - and in case you want to contribute to it: My work on this in the files section is up to date and has been updated just recently. Currently function_pointer_signature<R(*)(T0,T1)>::type is vector<T0,T1> function_pointer_signature<R(C::*)(T0,T1)>::type is vector<C,T0,T1> function_pointer_result<FuncPtr>::type is R (in both cases) Best regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckbu5h$acq$1@sea.gmane.org...
Alexander Nasonov wrote:
I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1>
as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1>
as_sequence<R(T0,T1)> reads great, but this would add a lot to the complexity of 'as_sequence':
First we have to idenitify if T is some sort of function (ptr/ref) type. Although there are ways to detect (not decompose, that is) functions and even member function pointers without using an unrolled cascades of specializations for different function arities, it requires a very standard compliant compiler. As we need to decompose the type and wrap its components into a vector in case it turns out to be a function anyway, we will instantiate one of these (more than 100) specializations.
I don't understand why this would be hard. Here's how I would do it: template<typename F> struct as_sequence_non_member { typedef typename mpl::push_front< typename function_arguments< F >::type, typename function_result< F >::type >::type type; }; template<typename F> struct as_sequence_member { typedef typename mpl::push_front< typename function_arguments< F >::type, typename function_class< F >::type >::type result; typedef typename mpl::push_front< result, typename function_result< F >::type >::type result; }; template<typename F> struct as_sequence : mpl::if_< is_member_function_pointer<F>, as_sequence_member<F> as_sequence_non_member >::type { }; Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting it: http://home.comcast.net/~jturkanis/function_traits/ It differs from your library as follows: - it splits up the metafunction signature into several metafunctions - it allows function types to be constructed from sequences - it doesn't handle volatility. It's not really meant to compete with your proposal -- I wrote it for a project I am currently working on. However, I'd like to know your opinion about it. Best Regards, Jonathan

Jonathan Turkanis wrote:
Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting it:
Wow! So many in one night! I'll be reading it a whole day :) I also wrote function_arguments some time ago because I needed it. In some situations it fits natural to your needs. For example: - add call_traits<>::param_type or add_reference to args and return a signature - add or remove some args from a signature - wrap some args Conversion to mpl::vector and back to signature would slow down a compilation. Why waste your time if function_arguments can be made as fast as mpl::vector after applying similar optimization techniques? -- Alexander Nasonov

"Alexander Nasonov" <alnsn@yandex.ru> wrote in message news:20041011052232.GA2287@x1000.localdomain...
Jonathan Turkanis wrote:
Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting it:
Wow! So many in one night! I'll be reading it a whole day :)
I also wrote function_arguments some time ago because I needed it. In some situations it fits natural to your needs. For example:
- add call_traits<>::param_type or add_reference to args and return a signature - add or remove some args from a signature - wrap some args
What I needed was the ability to add a parameter of type void* at the beginning of an arbitrary function pointer type. Of course I could have implemented this single transformation much more simply, but I like to generalize everything ;-)
Conversion to mpl::vector and back to signature would slow down a compilation. Why waste your time if function_arguments can be made as fast as mpl::vector after applying similar optimization techniques?
I'm not sure I understand your point. If you're saying that it's possible to implement mpl::sequence types specially tailored for function types, then I'm all for it, though I don't really see how to do it. OTOH, if you're saying that certain mpl algorithms should be reimplemented for function types, I'm not sure I agree, because it seems like reinventing the wheel. The regressions tests included in the code I posted contain about 200 static assertions, many involving mpl::equal, and they still compile quickly.
Alexander Nasonov
Jonathan

Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckbu5h$acq$1@sea.gmane.org...
Alexander Nasonov wrote:
I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1>
as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1>
as_sequence<R(T0,T1)> reads great, but this would add a lot to the complexity of 'as_sequence':
First we have to idenitify if T is some sort of function (ptr/ref) type. Although there are ways to detect (not decompose, that is) functions and even member function pointers without using an unrolled cascades of specializations for different function arities, it requires a very standard compliant compiler. As we need to decompose the type and wrap its components into a vector in case it turns out to be a function anyway, we will instantiate one of these (more than 100) specializations.
I don't understand why this would be hard. Here's how I would do it:
I meant what has to happen _inside_ the function_arguments metafunction. And the fact that it has to be defined at the point of this code:
template<typename F> struct as_sequence_non_member { typedef typename mpl::push_front< typename function_arguments< F >::type, typename function_result< F >::type >::type type; };
template<typename F> struct as_sequence_member { typedef typename mpl::push_front< typename function_arguments< F >::type, typename function_class< F >::type >::type result; typedef typename mpl::push_front< result, typename function_result< F >::type >::type result; };
template<typename F> struct as_sequence : mpl::if_< is_member_function_pointer<F>, as_sequence_member<F> as_sequence_non_member >::type { };
However, I guess you are talking about another as_sequence distinct from mpl::as_sequence...
Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting it:
http://home.comcast.net/~jturkanis/function_traits/
It differs from your library as follows:
- it splits up the metafunction signature into several metafunctions - it allows function types to be constructed from sequences - it doesn't handle volatility.
It's not really meant to compete with your proposal -- I wrote it for a project I am currently working on. However, I'd like to know your opinion about it.
I'll have a closer look at it this evening. Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckdcqh$imj$1@sea.gmane.org...
Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckbu5h$acq$1@sea.gmane.org...
Alexander Nasonov wrote:
I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1>
as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1>
as_sequence<R(T0,T1)> reads great, but this would add a lot to the complexity of 'as_sequence':
First we have to idenitify if T is some sort of function (ptr/ref) type. Although there are ways to detect (not decompose, that is) functions and even member function pointers without using an unrolled cascades of specializations for different function arities, it requires a very standard compliant compiler. As we need to decompose the type and wrap its components into a vector in case it turns out to be a function anyway, we will instantiate one of these (more than 100) specializations.
I don't understand why this would be hard. Here's how I would do it:
I meant what has to happen _inside_ the function_arguments metafunction. And the fact that it has to be defined at the point of this code:
<snip>
However, I guess you are talking about another as_sequence distinct from mpl::as_sequence...
Yes, I misunderstood the question. I don't like the idea of 'overloading' mpl::as_sequence this way, but generating sequences from function types vice versa seems like a legitimate request. I'm still not sure I see the difficulty, though.
Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting it:
http://home.comcast.net/~jturkanis/function_traits/
It differs from your library as follows:
- it splits up the metafunction signature into several metafunctions - it allows function types to be constructed from sequences - it doesn't handle volatility.
It's not really meant to compete with your proposal -- I wrote it for a
I should add to this: - it contains (almost) no broken compiler workarounds - it doesn't allow arities above BOOST_MPL_LIMIT_VECTOR_SIZE - it doesn't use the native TT macros. project
I am currently working on. However, I'd like to know your opinion about it.
I'll have a closer look at it this evening.
Thanks, Jonathan

Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckdcqh$imj$1@sea.gmane.org...
Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckbu5h$acq$1@sea.gmane.org...
Alexander Nasonov wrote:
I have one addition to '[type_traits] "member_function_pointer_traits" ?' thread started long time ago (29 Jul 2004) by Tobias Schwinger. Is it makes sense to modify as_sequence to convert function type into a sequence? Eg: as_sequence<R (T0,T1)> ---> vector<R,T0,T1> as_sequence<R(*)(T0,T1)> ---> vector<R,T0,T1> as_sequence<R(&)(T0,T1)> ---> vector<R,T0,T1>
as_sequence<R(C::*)(T0,T1)> ---> vector<R,C,T0,T1>
as_sequence<R(T0,T1)> reads great, but this would add a lot to the complexity of 'as_sequence':
First we have to idenitify if T is some sort of function (ptr/ref) type. Although there are ways to detect (not decompose, that is) functions and even member function pointers without using an unrolled cascades of specializations for different function arities, it requires a very standard compliant compiler. As we need to decompose the type and wrap its components into a vector in case it turns out to be a function anyway, we will instantiate one of these (more than 100) specializations.
I don't understand why this would be hard. Here's how I would do it:
I meant what has to happen _inside_ the function_arguments metafunction. And the fact that it has to be defined at the point of this code:
<snip>
However, I guess you are talking about another as_sequence distinct from mpl::as_sequence...
Yes, I misunderstood the question. I don't like the idea of 'overloading' mpl::as_sequence this way, but generating sequences from function types vice versa seems like a legitimate request. I'm still not sure I see the difficulty, though.
Yes, indeed. I was takling about the possiblilty of an 'mpl::as_sequence' "feature injection"...
Last night I realized I needed the ability to manipulate function types as sequences, so I wrote a small library to do it. I just finished documenting
it:
http://home.comcast.net/~jturkanis/function_traits/
It differs from your library as follows:
- it splits up the metafunction signature into several metafunctions - it allows function types to be constructed from sequences - it doesn't handle volatility.
I should add to this:
- it contains (almost) no broken compiler workarounds - it doesn't allow arities above BOOST_MPL_LIMIT_VECTOR_SIZE - it doesn't use the native TT macros.
OK.
It's not really meant to compete with your proposal -- I wrote it for a
Why not ?! If it's undoubtfully better it should be used instead. I don't think it is that _clearly_ better, yet. Although it has some advantages... Feel free to read / use / change or just deprecate my code in order to take it there ;+).
project
That's about the same motivation which made me work on it...
I am currently working on. However, I'd like to know your opinion about it.
I'll have a closer look at it this evening.
I'll try to arrange my thoughts about it top down. I'll also try to combine the ideas from this discussion and my proposal with it, after the analysis: JTFT: ----- First of all: _very_ nice documentation (by the way: you do not manually code the syntax highlighting, do you ? ;+). The interface looks very well to me, too. It conforms to the concepts of the Type Traits library (although it does not use the TT macros, as you said - but this should not be too hard to change). It is definitely an improvement compared to the current function_traits. I very much like the ability to modify/synthesize function (pointer) types. However, I am not fully convinced this interface is the best way to archieve this, yet. I will discuss my suggestions below. Looking at the implementation I think there is a lot of redundancy. There is one cascade for references, one for pointers, one for function (non ref/ptr) types and the same for synthesizing once again. If you want to use more of them at the same time, the code which needs to be processed sums up and takes its toll (consider for example using it to automatically register event handlers within a GUI framework where there are at least a few hundred translation units). Comparsion (JTFT versus TSFT): ------------------------------ The JTFT separate function I/O signatures into result, arguments and optionally class. TSFT only separates the input signature from the result. I have no idea which approach is better as there are applications where JTFT is more convenient (implementing closures) or where TSFT is more convenient ((full) argument binding). Both interfaces semantically make sense to me. While I read it now - I think I like the JTFT interface better... What were your thoughts on this design ? The JTFT introduce a new cascade of code for each kind of "signature type" (used in the following text as defined in the JTFT docs). The TSFT use one common backend for everything. The TSFT do not address function types and function references. The idea behind it was: using add_pointer / remove_reference may be better. The TSFT common backend comes with a price, too: It depends on mpl::vector up to BOOST_TT_FUNCTION_MAX_ARITY to be included. However, I think the backend part of TSFT is more simple and better. Further suggestions: -------------------- 1. Merge the best of both of our approaches 1.1. Implement the classification/decomposition interface of JTFT with the TSFT (or similar) backend. 1.1.1. The TSFT needs to be adjusted slightly to simplify the more fine grained separation of result,args and class. 1.2. use the native TT macros to publish the traits classes 1.3. handle volatility 2. Strip out the synthesis part and replace it with an mpl-sequence implemenation backed with (all) signature types. 3. Use this instead of mpl::vector in all cases. Step 2 is not that new. Alexander brought it up (well at least the base) when we started this discussion. I did find it too complicated and tried to keep things "safe and simple" in my proposal (it was meant as an extension to Type Traits rather than MPL ;+). However, if you really want to go that far in terms of modifying/synthesizing signature types, I believe this is the right way to go. One last note: -------------- The imperative used in the previous section is not meant as harsh as it may sound. So the section should be read as my todo list for the project: "combine the best parts of JTFT and TSFT into FT". OK - enough for now... Best regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote:
Jonathan Turkanis wrote:
It's not really meant to compete with your proposal -- I wrote it for a
Why not ?! If it's undoubtfully better it should be used instead. I don't think it is that _clearly_ better, yet. Although it has some advantages...
I just meant that it wasn't intended to supplant your proposal. I'm happy to work together with you, or to let you steal anything you like from my code ;-)
Feel free to read / use / change or just deprecate my code in order to take it there ;+).
Thanks. I'm feeling freer already.
First of all: _very_ nice documentation (by the way: you do not manually code the syntax highlighting, do you ? ;+).
I have keyboard shortcuts for the various categories.
Looking at the implementation I think there is a lot of redundancy. There is one cascade for references, one for pointers, one for function (non ref/ptr) types and the same for synthesizing once again.
Right. For some reason it didn't occur to me to use add/remove pointer/reference, as you mention below. I wrote the implementation fast, and it's so easy to copy and paste ;-)
Comparsion (JTFT versus TSFT): ------------------------------
The JTFT separate function I/O signatures into result, arguments and optionally class. TSFT only separates the input signature from the result. I have no idea which approach is better as there are applications where JTFT is more convenient (implementing closures) or where TSFT is more convenient ((full) argument binding). Both interfaces semantically make sense to me. While I read it now - I think I like the JTFT interface better... What were your thoughts on this design ?
To me it's more natural not to consider the implicit object pointer position to be part of the argument list, which is why I chose my design. Whichever is implemented from scratch, the other can be implemented easily as a wrapper.
The JTFT introduce a new cascade of code for each kind of "signature type" (used in the following text as defined in the JTFT docs). The TSFT use one common backend for everything. The TSFT do not address function types and function references. The idea behind it was: using add_pointer / remove_reference may be better. The TSFT common backend comes with a price, too: It depends on mpl::vector up to BOOST_TT_FUNCTION_MAX_ARITY to be included. However, I think the backend part of TSFT is more simple and better.
I think you're clearly correct about only providing specializations for one of the three type/pointer/reference family. Otherwise, superficial differences asside, our implementations are very similar. The one key difference is that you use overload resolution and sizeof to implement the boolean metafunctions. Since this information is already available in decompose, I'm not sure why you do this. Is it for efficiency?
Further suggestions: --------------------
1. Merge the best of both of our approaches 1.1. Implement the classification/decomposition interface of JTFT with the TSFT (or similar) backend.
Sounds good to me.
1.1.1. The TSFT needs to be adjusted slightly to simplify the more fine grained separation of result,args and class. 1.2. use the native TT macros to publish the traits classes
Good.
1.3. handle volatility
Also good. I'm interested to know, though, whether this is simply a matter of being comprehensive -- which is fine with me -- or whether you think there are important use cases.
2. Strip out the synthesis part and replace it with an mpl-sequence implemenation backed with (all) signature types.
3. Use this instead of mpl::vector in all cases.
Step 2 is not that new. Alexander brought it up (well at least the base) when we started this discussion.
Just to make sure we're on the same page, are you refering to these comments: "Alexander Nasonov" <alnsn@yandex.ru> wrote:
Conversion to mpl::vector and back to signature would slow down a compilation. Why waste your time if function_arguments can be made as fast as mpl::vector after applying similar optimization techniques?
?
I did find it too complicated and tried to keep things "safe and simple" in my proposal (it was meant as an extension to Type Traits rather than MPL ;+). However, if you really want to go that far in terms of modifying/synthesizing signature types, I believe this is the right way to go.
This is fine with me. Unfortunately, I'm probably not familiar enough with mpl optimization techniques to write a sequence type that will yield better performance than translating to and from mpl::vector. I hope you or Alexander have a better grasp of these issues then I do. I does sound fun, though.
One last note: --------------
The imperative used in the previous section is not meant as harsh as it may sound. So the section should be read as my todo list for the project: "combine the best parts of JTFT and TSFT into FT".
You don't have to worry about offending my sensibilities. I'm unflappable. ;-)
Best regards,
Tobias
Jonathan

Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote:
Jonathan Turkanis wrote:
It's not really meant to compete with your proposal -- I wrote it for a
Why not ?! If it's undoubtfully better it should be used instead. I don't think it is that _clearly_ better, yet. Although it has some advantages...
I just meant that it wasn't intended to supplant your proposal. I'm happy to work together with you, or to let you steal anything you like from my code ;-)
Feel free to read / use / change or just deprecate my code in order to take it there ;+).
Thanks. I'm feeling freer already.
First of all: _very_ nice documentation (by the way: you do not manually code the syntax highlighting, do you ? ;+).
I have keyboard shortcuts for the various categories.
Looking at the implementation I think there is a lot of redundancy. There is one cascade for references, one for pointers, one for function (non ref/ptr) types and the same for synthesizing once again.
Right. For some reason it didn't occur to me to use add/remove pointer/reference, as you mention below. I wrote the implementation fast, and it's so easy to copy and paste ;-)
Comparsion (JTFT versus TSFT): ------------------------------
The JTFT separate function I/O signatures into result, arguments and optionally class. TSFT only separates the input signature from the result. I have no idea which approach is better as there are applications where JTFT is more convenient (implementing closures) or where TSFT is more convenient ((full) argument binding). Both interfaces semantically make sense to me. While I read it now - I think I like the JTFT interface better... What were your thoughts on this design ?
To me it's more natural not to consider the implicit object pointer position to be part of the argument list, which is why I chose my design. Whichever is implemented from scratch, the other can be implemented easily as a wrapper.
Even though I thought quite a bit about separating them while writing it - and I decided not to do so. Your interface does seem more natural and thus preferable to me.
The JTFT introduce a new cascade of code for each kind of "signature type" (used in the following text as defined in the JTFT docs). The TSFT use one common backend for everything. The TSFT do not address function types and function references. The idea behind it was: using add_pointer / remove_reference may be better. The TSFT common backend comes with a price, too: It depends on mpl::vector up to BOOST_TT_FUNCTION_MAX_ARITY to be included. However, I think the backend part of TSFT is more simple and better.
I think you're clearly correct about only providing specializations for one of the three type/pointer/reference family. Otherwise, superficial differences asside, our implementations are very similar. The one key difference is that you use overload resolution and sizeof to implement the boolean metafunctions. Since this information is already available in decompose, I'm not sure why you do this. Is it for efficiency?
In fact, I don't. It's only done this way for compilers which won't allow these partial specializations otherwise. The naming of these files is probably confusing - "_fallback" could be more clear than "_classify"...
Further suggestions: --------------------
1. Merge the best of both of our approaches 1.1. Implement the classification/decomposition interface of JTFT with the TSFT (or similar) backend.
Sounds good to me.
1.1.1. The TSFT needs to be adjusted slightly to simplify the more fine grained separation of result,args and class. 1.2. use the native TT macros to publish the traits classes
Good.
1.3. handle volatility
Also good. I'm interested to know, though, whether this is simply a matter of being comprehensive -- which is fine with me -- or whether you think there are important use cases.
2. Strip out the synthesis part and replace it with an mpl-sequence implemenation backed with (all) signature types.
3. Use this instead of mpl::vector in all cases.
Step 2 is not that new. Alexander brought it up (well at least the base) when we started this discussion.
Just to make sure we're on the same page, are you refering to these comments:
"Alexander Nasonov" <alnsn@yandex.ru> wrote:
Conversion to mpl::vector and back to signature would slow down a compilation. Why waste your time if function_arguments can be made as fast as mpl::vector after applying similar optimization techniques?
?
No. It was in the thread I brought up that this is missing. Alexander suggested function_signature<T> could model an mpl sequence itself instead of having function_signature<T>::type be an mpl sequence.
I did find it too complicated and tried to keep things "safe and simple" in my proposal (it was meant as an extension to Type Traits rather than MPL ;+). However, if you really want to go that far in terms of modifying/synthesizing signature types, I believe this is the right way to go.
This is fine with me. Unfortunately, I'm probably not familiar enough with mpl optimization techniques to write a sequence type that will yield better performance than translating to and from mpl::vector. I hope you or Alexander have a better grasp of these issues then I do. I does sound fun, though.
A basic imlpementation could look just like 'vector' but with a few typedefs more... As you said: it sounds fun - and is likely to be slightly better. However, I don't think it's that very important - as the case of modifying signature types is not likely to happen that often (correct me if I'm wrong). I would vote for this even without a special sequence, that is...
One last note: --------------
The imperative used in the previous section is not meant as harsh as it may sound. So the section should be read as my todo list for the project: "combine the best parts of JTFT and TSFT into FT".
You don't have to worry about offending my sensibilities. I'm unflappable. ;-)
Good to hear ;+). Who's doing the megre, then ? I'll be quite busy until the middle of next week and won't get very much done before it... Regards, Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckg0rf$t0m$1@sea.gmane.org...
Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote:
Comparsion (JTFT versus TSFT): ------------------------------
The JTFT separate function I/O signatures into result, arguments and optionally class. TSFT only separates the input signature from the result. I have no idea which approach is better as there are applications where JTFT is more convenient (implementing closures) or where TSFT is more convenient ((full) argument binding). Both interfaces semantically make sense to me. While I read it now - I think I like the JTFT interface better... What were your thoughts on this design ?
To me it's more natural not to consider the implicit object pointer position to be part of the argument list, which is why I chose my design. Whichever is implemented from scratch, the other can be implemented easily as a wrapper.
Even though I thought quite a bit about separating them while writing it - and I decided not to do so. Your interface does seem more natural and thus preferable to me.
Okay, it's settled. ;-)
2. Strip out the synthesis part and replace it with an mpl-sequence implemenation backed with (all) signature types.
Step 2 is not that new. Alexander brought it up (well at least the base) when we started this discussion.
Just to make sure we're on the same page, are you refering to these comments:
"Alexander Nasonov" <alnsn@yandex.ru> wrote:
Conversion to mpl::vector and back to signature would slow down a compilation. Why waste your time if function_arguments can be made as fast as mpl::vector after applying similar optimization techniques?
?
No. It was in the thread I brought up that this is missing. Alexander suggested function_signature<T> could model an mpl sequence itself instead of having function_signature<T>::type be an mpl sequence.
Okay, I searched but couldn't find it.
I did find it too complicated and tried to keep things "safe and simple" in my proposal (it was meant as an extension to Type Traits rather than MPL ;+). However, if you really want to go that far in terms of modifying/synthesizing signature types, I believe this is the right way to go.
This is fine with me. Unfortunately, I'm probably not familiar enough with mpl optimization techniques to write a sequence type that will yield better performance than translating to and from mpl::vector. I hope you or Alexander have a better grasp of these issues then I do. I does sound fun, though.
A basic imlpementation could look just like 'vector' but with a few typedefs more...
Okay.
As you said: it sounds fun - and is likely to be slightly better. However, I don't think it's that very important - as the case of modifying signature types is not likely to happen that often (correct me if I'm wrong). I would vote for this even without a special sequence, that is...
If the efficiency advantages don't depend on removing the indirection from function_signature<T>::type, then we can consider implementing a native sequence type as a premature optimization.
Who's doing the megre, then ?
I'll be quite busy until the middle of next week and won't get very much done before it...
I'll be out of town until next friday, so let's suspend this discussion until then. Best Regards, Jonathan

Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:ckg0rf$t0m$1@sea.gmane.org...
No. It was in the thread I brought up that this is missing. Alexander suggested function_signature<T> could model an mpl sequence itself instead of having function_signature<T>::type be an mpl sequence.
Okay, I searched but couldn't find it.
I did find it too complicated and tried to keep things "safe and simple" in my proposal (it was meant as an extension to Type Traits rather than MPL ;+). However, if you really want to go that far in terms of modifying/synthesizing signature types, I believe this is the right way to go.
This is fine with me. Unfortunately, I'm probably not familiar enough with mpl optimization techniques to write a sequence type that will yield better performance than translating to and from mpl::vector. I hope you or Alexander have a better grasp of these issues then I do. I does sound fun, though.
A basic imlpementation could look just like 'vector' but with a few typedefs more...
Okay.
As you said: it sounds fun - and is likely to be slightly better. However, I don't think it's that very important - as the case of modifying signature types is not likely to happen that often (correct me if I'm wrong). I would vote for this even without a special sequence, that is...
If the efficiency advantages don't depend on removing the indirection from function_signature<T>::type, then we can consider implementing a native sequence type as a premature optimization.
I would prefer to keep ::type (because of mpl::eval_if, mpl::and, ...). The advantage would be to get rid of (at least) one specialization cascade for the synthesis. I'm not really sure it's worth maintaining an mpl-sequence implementation (although I think it would be more elegant), since I don't know if the type synthesis feature will be used that frequently. Could you name a few typical appications ? While talking about appications: I think I did not give an example for the usefulness of volatility support, yet: Let's (again) consider using this for an eventing system with a metaprogrammed facility to ease the registration of handler methods. If it runs in a multithreaded context 'volatile' would come handy to tag that a function needs to be synchonized (it would even suit semantically, somehow). Put abstract it's yet another flag for (nearly) free.
Who's doing the megre, then ?
I'll be quite busy until the middle of next week and won't get very much done before it...
I'll be out of town until next friday, so let's suspend this discussion until then.
OK. Greetings, Tobias

Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message
However, I guess you are talking about another as_sequence distinct from mpl::as_sequence...
Yes, I misunderstood the question. I don't like the idea of 'overloading' mpl::as_sequence this way, but generating sequences from function types vice versa seems like a legitimate request. I'm still not sure I see the difficulty though.
Yes, I mean mpl::as_sequence. I know, overloading it this way is not a best idea but, I can think of mpl::as_sequence only as a sugar. That is, if template X accepts MPL sequence, you can pass an ordinary type if X has mpl::as_sequence underneath: X<mpl::vector<int> > // 1 X<int> // 2 - sugar for 1 Sequence concept is mixed up with ordinary types but if you tell a user about it, they can accept it. If mpl::as_sequence treated function types as I suggest, it could introduce more sugar: X<int(char)> // 3 - sugar for mpl::vector<int,char> but this could confuse a user. -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> writes:
Jonathan Turkanis wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message
However, I guess you are talking about another as_sequence distinct from mpl::as_sequence...
Yes, I misunderstood the question. I don't like the idea of 'overloading' mpl::as_sequence this way, but generating sequences from function types vice versa seems like a legitimate request. I'm still not sure I see the difficulty though.
Yes, I mean mpl::as_sequence. I know, overloading it this way is not a best idea but, I can think of mpl::as_sequence only as a sugar. That is, if template X accepts MPL sequence, you can pass an ordinary type if X has mpl::as_sequence underneath:
X<mpl::vector<int> > // 1 X<int> // 2 - sugar for 1
Sequence concept is mixed up with ordinary types but if you tell a user about it, they can accept it. If mpl::as_sequence treated function types as I suggest, it could introduce more sugar:
X<int(char)> // 3 - sugar for mpl::vector<int,char>
but this could confuse a user.
FWIW, we didn't cover as_sequence in the book because we really couldn't come up with a use case that justified the non-uniformity in generic programs. If the type you pass happens to be a sequence already it gets treated differently :(. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
FWIW, we didn't cover as_sequence in the book because we really couldn't come up with a use case that justified the non-uniformity in generic programs. If the type you pass happens to be a sequence already it gets treated differently :(.
I don't quite understand your negative reaction on difference. A lot of things are different :) If you couldn't find a good use case for generic programs, may be we could try find something interesting for "real" (I mean not generic) programs? -- Alexander Nasonov

Alexander Nasonov wrote:
David Abrahams wrote:
FWIW, we didn't cover as_sequence in the book because we really couldn't come up with a use case that justified the non-uniformity in generic programs. If the type you pass happens to be a sequence already it gets treated differently :(.
I don't quite understand your negative reaction on difference. A lot of things are different :) If you couldn't find a good use case for generic programs, may be we could try find something interesting for "real" (I mean not generic) programs?
I have no opinion if as_sequence should be overloaded this way, or not, but I'd like the function pointer type -> sequence metafunction. As example, I'm working on Boost.Plugin library, and I'd prefer to change the current syntax for describing plugin's constructor arguments: template<> class virtual_constructors<MyBasePluginClass> { typedef mpl::vector< mpl::vector<int>, mpl::vector<double> > type; }; to template<> class virtual_constructors<MyBasePluginClass> { typedef mpl::vector<ctor (int), ctor(double)> type; }; (Where 'ctor' is dummy syntax sugar type). - Volodya

Alexander Nasonov <alnsn@yandex.ru> writes:
David Abrahams wrote:
FWIW, we didn't cover as_sequence in the book because we really couldn't come up with a use case that justified the non-uniformity in generic programs. If the type you pass happens to be a sequence already it gets treated differently :(.
I don't quite understand your negative reaction on difference. A lot of things are different :) If you couldn't find a good use case for generic programs, may be we could try find something interesting for "real" (I mean not generic) programs?
A solution looking for a problem? The one case we've seen in real designs is in boost::variant, and in that case I agree with Peter Dimov that the genericity breakage is unacceptable. http://lists.boost.org/MailArchives/boost/msg55143.php -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (5)
-
Alexander Nasonov
-
David Abrahams
-
Jonathan Turkanis
-
Tobias Schwinger
-
Vladimir Prus