[Boost.TypeTraits] Adding specialisations
I'm wondering if finding the need to add specialisations of
boost::detail::function_traits_helper is a result of missing headers,
incorrect usage or just things that have not been added to
Boost.TypeTraits on purpose?
I'm using Boost 1.34.0 RC and MSVC 8.1 SP1.
The first set can be seen on
http://www.boostcookbook.com/Recipe:/1234841 and the second set on
http://www.boostcookbook.com/Recipe:/1234968
namespace boost {
namespace detail {
template<typename R>
struct function_traits_helper
Kirit Sælensminde wrote:
I'm wondering if finding the need to add specialisations of boost::detail::function_traits_helper is a result of missing headers, incorrect usage or just things that have not been added to Boost.TypeTraits on purpose?
Not added on purpose: function_traits works for *function types*, and not
*pointer to function types*.
So:
functions_traits
John Maddock wrote:
Kirit Sælensminde wrote:
I'm wondering if finding the need to add specialisations of boost::detail::function_traits_helper is a result of missing headers, incorrect usage or just things that have not been added to Boost.TypeTraits on purpose?
Not added on purpose: function_traits works for *function types*, and not *pointer to function types*.
So:
functions_traits
OK. function_traits bad: argument not a function type. You can always use remove_pointer to strip a function-pointer down to a function type.
HTH, John.
That makes perfect sense, unfortunately it doesn't help. From the worker thread example I've removed the specialisation for R(**)(void) - I can't work out why there is a double indirection there, but it might well be contributing to the problem. I've also changed the functor that does the type handling to this: template< typename F > boost::shared_ptr< Future< typename boost::function_traits< F
::result_type > > operator()( F f ) { return run< typename boost::function_traits< typename boost::remove_pointer< F >::type >::result_type >( f ); }
And even to this: template< typename F > boost::shared_ptr< Future< typename boost::function_traits< F
::result_type > > operator()( F f ) { return run< typename boost::function_traits< typename boost::remove_pointer< typename boost::remove_pointer< F >::type >::type ::result_type >( f ); }
I get exactly the same error in either case:
1>e:\dev\trunk\clients\kirit saelensminde\samples\boost cookbook\worker
thread\worker thread.cpp(112) : warning C4355: 'this' : used in base
member initializer list
1>e:\dev\boost\install\basic\include\boost-1_34\boost\type_traits\function_traits.hpp(170)
: error C2504: 'boost::detail::function_traits_helper<Function>' : base
class undefined
1> with
1> [
1> Function=int (__cdecl **)(void)
1> ]
1> e:\dev\trunk\clients\kirit saelensminde\samples\boost
cookbook\worker thread\worker thread.cpp(209) : see reference to class
template instantiation 'boost::function_traits<Function>' being compiled
1> with
1> [
1> Function=int (__cdecl *)(void)
1> ]
1>e:\dev\trunk\clients\kirit saelensminde\samples\boost cookbook\worker
thread\worker thread.cpp(209) : error C2893: Failed to specialize
function template
'boost::shared_ptr
Kirit Sælensminde wrote:
That makes perfect sense, unfortunately it doesn't help.
From the worker thread example I've removed the specialisation for R(**)(void) - I can't work out why there is a double indirection there, but it might well be contributing to the problem.
I've also changed the functor that does the type handling to this:
template< typename F > boost::shared_ptr< Future< typename boost::function_traits< F
::result_type > > operator()( F f ) { return run< typename boost::function_traits< typename boost::remove_pointer< F >::type >::result_type >( f ); }
The return type should probably be:
boost::shared_ptr< Future< typename boost::function_traits< typename
boost::remove_pointer<F>::type>::result_type > >
But you may want to wrap that up in a small traits class to avoid repeated
typing :-)
HTH John.
PS My simple test case is this:
#include
John Maddock wrote:
Kirit Sælensminde wrote:
That makes perfect sense, unfortunately it doesn't help.
From the worker thread example I've removed the specialisation for R(**)(void) - I can't work out why there is a double indirection there, but it might well be contributing to the problem.
I've also changed the functor that does the type handling to this:
template< typename F > boost::shared_ptr< Future< typename boost::function_traits< F
::result_type > > operator()( F f ) { return run< typename boost::function_traits< typename boost::remove_pointer< F >::type >::result_type >( f ); }
The return type should probably be:
boost::shared_ptr< Future< typename boost::function_traits< typename boost::remove_pointer<F>::type>::result_type > >
You're right. What a muppet I am :( I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ), whereas I'm thinking of it as something to examine any unambiguous callable item. I.e. function pointers, member functions, all kinds of lambdas etc. What I've found is that if I add the specialisations to boost::details::function_traits_helper I *can* use it how I expect. Is the reason for leaving them out? Something technical that I'm missing so I'm just storing up trouble for myself in the long run? What is the proper way of doing this? Given a choice between having to write lots of overloaded functions to deal with the different possibilities every time I want to write a function that needs to do some type deduction and adding specialisations just once I know which feels most appealing. For example, if I've understood the mem_fn documentation properly (and I'm by no means sure that I have) it seems I have to either say that users of safe_call need to wrap the member up like this: safe_call( ptr, boost::mem_fn( &foo::bar ) )( a1, a2 ); Or I have to overload safe_call for every parameter combination that there might be: template< typename C, typename R > safe_call( C *ptr, R (C::*)() ); template< typename C, typename R, typename A1 > safe_call( C *ptr, R (C::*)( A1 ) ); It seems simpler to handle this by extending boost::function_traits to deal with member functions - which is what I've done. I'm thinking I'm missing some other way of doing this. K
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ),
Correct.
whereas I'm thinking of it as something to examine any unambiguous callable item. I.e. function pointers, member functions, all kinds of lambdas etc.
What I've found is that if I add the specialisations to boost::details::function_traits_helper I *can* use it how I expect.
Is the reason for leaving them out? Something technical that I'm missing so I'm just storing up trouble for myself in the long run?
What is the proper way of doing this? Given a choice between having to write lots of overloaded functions to deal with the different possibilities every time I want to write a function that needs to do some type deduction and adding specialisations just once I know which feels most appealing.
How about result_of: http://www.boost.org/libs/utility/utility.htm#result_of ? John
John Maddock wrote:
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ),
Correct.
What is the reason for the restriction? It seems to make a number of common things unnecessarily verbose. For example, always having to wrap a some generic callable F with "typename boost::remove_pointer< F >::type". We don't need to do that if when we use the F. Higher order functions that take things like predicates allow us to just use the callable objects, why can't we do the same thing when we want to find out which types are involved? It makes a lot of idioms copied from functional programming much more verbose to do than it seems they really need to be. As I say, by adding the specialisations myself I can do all sorts of interesting things that are too difficult to do otherwise. For example, by adding specialisations for R(**)(...) I can use boost::function_traits with function pointers without needing to remember the remove_pointer. And by adding specialisations for boost::_bi::bind_t (which I probably have wrong, but stil) I can use boost::function_traits with the result of a boost::bind. What is wrong with that? Or do we need a new library Boost.CallableTraits to deal with it? K BTW boost::result_of does help with the verbiage if include the remove_pointer, but it still doesn't work with the result of a boost::bind.
Kirit Sælensminde wrote:
John Maddock wrote:
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ), Correct.
What is the reason for the restriction?
Well theoretically we could have a 'remove_member_pointer' as well. Unfortunately it's not easily implementable without running into a lot of compiler-specific trouble. The Boost CVS/SVN contains a library that is dedicated to deal with this trouble. See $(BOOST_ROOT)/libs/function_types/docs/html/index.html it should contain easily readable traits for all the use cases you mentioned in this thread. Regards, Tobias
Tobias Schwinger wrote:
Kirit Sælensminde wrote:
John Maddock wrote:
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ), Correct. What is the reason for the restriction?
Well theoretically we could have a 'remove_member_pointer' as well. Unfortunately it's not easily implementable without running into a lot of compiler-specific trouble.
The Boost CVS/SVN contains a library that is dedicated to deal with this trouble. See
$(BOOST_ROOT)/libs/function_types/docs/html/index.html
it should contain easily readable traits for all the use cases you mentioned in this thread.
Thanks Tobias, I'll grab that from SVN and take a look. Is this slated to be part of 1.35? K
Kirit Sælensminde wrote:
John Maddock wrote:
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ),
Correct.
What is the reason for the restriction?
Well I didn't write that trait.... but the general idea was that the type traits library should encapsulate the C++ type system only, and that higher level functionality would be provided later.
BTW boost::result_of does help with the verbiage if include the remove_pointer, but it still doesn't work with the result of a boost::bind.
:-( The trouble is, I'm not sure that there's any way to actually implement that in the general sense without full introspection in C++, and/or a working typeof operator. However, I would have expected Boost.Bind to play nice and work with result_of. Sorry I can't be more helpful at present. John.
John Maddock wrote:
Kirit Sælensminde wrote:
John Maddock wrote:
Kirit Sælensminde wrote:
I think I have a misunderstanding of what the boost::function_traits is doing. From your explanation it seems that boost::function_traits is there to examine only function signatures where a function type is of the form R( A1, A2, etc. ), Correct. What is the reason for the restriction?
Well I didn't write that trait.... but the general idea was that the type traits library should encapsulate the C++ type system only, and that higher level functionality would be provided later.
BTW boost::result_of does help with the verbiage if include the remove_pointer, but it still doesn't work with the result of a boost::bind.
:-(
The trouble is, I'm not sure that there's any way to actually implement that in the general sense without full introspection in C++, and/or a working typeof operator. However, I would have expected Boost.Bind to play nice and work with result_of.
Sorry I can't be more helpful at present.
Thanks a lot for your time and explanations. Now that I understand more what boost::function_traits is trying to do it makes a lot more sense. The documentation of function_traits (at least at http://www.boost.org/doc/html/boost_typetraits/reference.html#boost_typetrai... ) has no indication of what it is meant to do. Maybe something along the lines of this could be added to the documentation (the function pointer restriction is not very visible as the last example - it's only now that I've looked at the documentation a lot more closely that I've noticed it was there at all): "function_traits is intended to introspect only C++ functions of the form R (), R( A1 ), R ( A1, ... etc. ) and not function pointers or class member functions. To convert a function pointer type to a suitable type use boost::remove_pointer." I hesitate to add something about using boost::mem_fn to convert a member function to a suitable type as I've not been able to get it to do it yet. I'm guessing that boost::mem_fn is intended to do one of the following two type transformations, but again it isn't clear from the documentation. R (C::*)( ... ) const -> R ( const C *, ... ) R (C::*)( ... ) -> R ( C *, ... ) But maybe it is this: R (C::*)( ... ) const -> R (*)( const C *, ... ) R (C::*)( ... ) -> R (*)( C *, ... ) Or one of the above with a C& instead of a C*. Maybe a note on which type transformation it does should be in the documentation? K
Kirit Sælensminde wrote:
Thanks a lot for your time and explanations. Now that I understand more what boost::function_traits is trying to do it makes a lot more sense.
The documentation of function_traits (at least at http://www.boost.org/doc/html/boost_typetraits/reference.html#boost_typetrai... ) has no indication of what it is meant to do. Maybe something along the lines of this could be added to the documentation (the function pointer restriction is not very visible as the last example - it's only now that I've looked at the documentation a lot more closely that I've noticed it was there at all):
"function_traits is intended to introspect only C++ functions of the form R (), R( A1 ), R ( A1, ... etc. ) and not function pointers or class member functions. To convert a function pointer type to a suitable type use boost::remove_pointer."
Will do.
I hesitate to add something about using boost::mem_fn to convert a member function to a suitable type as I've not been able to get it to do it yet. I'm guessing that boost::mem_fn is intended to do one of the following two type transformations, but again it isn't clear from the documentation.
mem_fn does the same thing as std::mem_fn: it constructs a callable function object from a pointer to a member function, but without some of the limitations of the std version. John.
participants (3)
-
John Maddock
-
Kirit Sælensminde
-
Tobias Schwinger