[function_types] is there an equivalent for functors?

Hi all, I'm looking for code that does what boost::function_types::parameter_types does but for functors. Support for things such as boost::bind/lambda/function/signals(1&2)/etc and the standard binders and adaptors would be nice. I specifically want to be able to do something like: template<typename Functor> void f(const Functor &f) { typedef typename functor_params<Functor>::type params; // an mpl sequence const std::size_t arity = functor_arity<Functor>::value; // ... } I started writing code for this but I've come to the point where I can't see a way to support libraries such as boost::bind without relying on their implementation details. But perhaps something like this already exists? Thanks, Edd

On 7/5/2010 10:46 AM, Edd Dawson wrote:
Hi all,
I'm looking for code that does what boost::function_types::parameter_types does but for functors. Support for things such as boost::bind/lambda/function/signals(1&2)/etc and the standard binders and adaptors would be nice.
I specifically want to be able to do something like:
template<typename Functor> void f(const Functor &f) { typedef typename functor_params<Functor>::type params; // an mpl sequence const std::size_t arity = functor_arity<Functor>::value; // ... }
I started writing code for this but I've come to the point where I can't see a way to support libraries such as boost::bind without relying on their implementation details.
But perhaps something like this already exists?
Thanks,
Edd
At the outset that looks ill-defined, since function objects may generally be polymorphic (accept a variety of parameter types and arities, each combination potentially returning a different result type). For example, struct identity { template< class T > T operator()(T x) const { return x; } }; If you want restrict yourself to monomorphic function objects, then it might be possible, but I don't know of a generic way to obtain the information you're seeking. You can, however, get away with querying whether a function object can be called with a specific signature, though the machinery to do this is relatively complex. I think something working is found in Boost.Proto as "can_be_called". - Jeff

Jeffrey Lee Hellrung, Jr. wrote:
You can, however, get away with querying whether a function object can be called with a specific signature, though the machinery to do this is relatively complex. I think something working is found in Boost.Proto as "can_be_called". If the functor follow the result_of protocol, a traits can be made to test if a functor F can be called with arguments A0,..,An with a syntax like can_be_called<F(A0,...,An)>
Here is a sample implementation: http://codepad.org/H5CtU5sa

On Mon, Jul 5, 2010 at 2:18 PM, joel falcou <joel.falcou@lri.fr> wrote:
Jeffrey Lee Hellrung, Jr. wrote:
You can, however, get away with querying whether a function object can be called with a specific signature, though the machinery to do this is relatively complex. I think something working is found in Boost.Proto as "can_be_called".
If the functor follow the result_of protocol, a traits can be made to test if a functor F can be called with arguments A0,..,An with a syntax like can_be_called<F(A0,...,An)>
Here is a sample implementation:
And if you know a signature of a functor, you can use function_types directly with the signature. For example, template<typename Signature> void f(const boost::function<Signature> &f) { using boost::function_types::parameter_types; using boost::function_types::function_arity; typedef typename parameter_types<Signature>::type params; // an mpl sequence const std::size_t arity = function_arity<Signature>::value; // ... } Daniel Walker

On 7/5/2010 8:21 PM, Daniel Walker wrote:
And if you know a signature of a functor, you can use function_types directly with the signature. For example,
template<typename Signature> void f(const boost::function<Signature> &f) { using boost::function_types::parameter_types; using boost::function_types::function_arity;
typedef typename parameter_types<Signature>::type params; // an mpl sequence const std::size_t arity = function_arity<Signature>::value; // ... }
100 bonus points for implementing boost::bind support for me :) Kind regards, Edd

On Mon, Jul 5, 2010 at 3:36 PM, Edd Dawson <lists@mr-edd.co.uk> wrote:
On 7/5/2010 8:21 PM, Daniel Walker wrote:
And if you know a signature of a functor, you can use function_types directly with the signature. For example,
template<typename Signature> void f(const boost::function<Signature> &f) { using boost::function_types::parameter_types; using boost::function_types::function_arity;
typedef typename parameter_types<Signature>::type params; // an mpl sequence const std::size_t arity = function_arity<Signature>::value; // ... }
100 bonus points for implementing boost::bind support for me :)
No prob. Yeah, boost::function can store boost::bind objects... if you know the signature. Also, another thought, if the call operators on your function objects are not overloaded, you can do something like the following without having to know the signature. template<typename Functor, typename CallOperator> void f(const Functor &f, CallOperator) { using boost::function_types::parameter_types; using boost::function_types::function_arity; typedef typename parameter_types<CallOperator>::type params; // an mpl sequence const std::size_t arity = function_arity<CallOperator>::value; // ... } struct F { void operator()(int) {} }; int main() { f(F(), &F::operator()); } Daniel Walker

On 7/5/2010 8:53 PM, Daniel Walker wrote:
Also, another thought, if the call operators on your function objects are not overloaded, you can do something like the following without having to know the signature.
template<typename Functor, typename CallOperator> void f(const Functor&f, CallOperator) { using boost::function_types::parameter_types; using boost::function_types::function_arity;
typedef typename parameter_types<CallOperator>::type params; // an mpl sequence const std::size_t arity = function_arity<CallOperator>::value; // ... }
struct F { void operator()(int) {} };
int main() { f(F(),&F::operator()); }
That's a nice trick, thanks! I might be able to use that for the general case. Unfortunately a bind expression seems to have tens of overloads :( Kind regards, Edd

On 07/05/10 12:59, Jeffrey Lee Hellrung, Jr. wrote:
On 7/5/2010 10:46 AM, Edd Dawson wrote: [snip] You can, however, get away with querying whether a function object can be called with a specific signature, though the machinery to do this is relatively complex. I think something working is found in Boost.Proto as "can_be_called".
If you can use the gcc variadic template compiler, then this: http://preview.tinyurl.com/2453536 which is a variadic can_be_called, might be useful. -regards, Larry

On 7/5/2010 6:59 PM, Jeffrey Lee Hellrung, Jr. wrote:
On 7/5/2010 10:46 AM, Edd Dawson wrote:
Hi all,
I'm looking for code that does what boost::function_types::parameter_types does but for functors. Support for things such as boost::bind/lambda/function/signals(1&2)/etc and the standard binders and adaptors would be nice.
If you want restrict yourself to monomorphic function objects, then it might be possible, but I don't know of a generic way to obtain the information you're seeking.
Ah yes, I didn't mean to imply that I was seeking a truly generic solution. A "sanctioned" collection of template specializations for common functor types would be fine. The standard function objects have internal typedefs such as argument_type, second_argument_type and so on for this kind of deduction. Some of the boost functor libraries follow this convention and extend it to cope with more than two parameters... but others don't :( Actually, I don't strictly *need* such a facility, but it would my little library a bit nicer to use e.g. connect(slider, SIGNAL(valueChanged(int)), bind(&on_slide, ref(value), _1))); vs. connectx<void (int)>(slider, SIGNAL(valueChanged(int)), bind(&on_slide, ref(value), _1)); (it's for connecting Qt signals to functions/functors without going through the extra bother of the moc step at build time).
You can, however, get away with querying whether a function object can be called with a specific signature, though the machinery to do this is relatively complex. I think something working is found in Boost.Proto as "can_be_called".
Unfortunately, my problem is that I'm handed an almost arbitrary functor and need to be able to deduce the parameter types from the functor's type alone. This is because Qt's "meta machinery" forces me eventually to cast a bunch of void*s to pointers whose types are given by the functor parameters, in order to actually call the functor. Without having a database of types upfront and employing an exponential algorithm, can_be_called is probably not going to get me what I want, right? Cheers, Edd

On 7/5/2010 11:33 AM, Edd Dawson wrote:
On 7/5/2010 6:59 PM, Jeffrey Lee Hellrung, Jr. wrote:
On 7/5/2010 10:46 AM, Edd Dawson wrote:
Hi all,
I'm looking for code that does what boost::function_types::parameter_types does but for functors. Support for things such as boost::bind/lambda/function/signals(1&2)/etc and the standard binders and adaptors would be nice.
If you want restrict yourself to monomorphic function objects, then it might be possible, but I don't know of a generic way to obtain the information you're seeking.
Ah yes, I didn't mean to imply that I was seeking a truly generic solution. A "sanctioned" collection of template specializations for common functor types would be fine.
You can create a trait which exposes the parameter and return types and specialize it for the function objects you'd be interested in using. E.g., template< class T > struct fn_traits; template< ... > struct fn_traits< boost::detail::binder< ... > > { ... }; Not the most robust solution (in that you may be relying on implementation details), but it might get you far enough... [...]
Without having a database of types upfront and employing an exponential algorithm, can_be_called is probably not going to get me what I want, right?
I agree, I don't think it helps in this case. - Jeff

On 10-07-05 2:33 PM, Edd Dawson wrote:
Actually, I don't strictly *need* such a facility, but it would my little library a bit nicer to use e.g.
connect(slider, SIGNAL(valueChanged(int)), bind(&on_slide, ref(value), _1))); vs. connectx<void (int)>(slider, SIGNAL(valueChanged(int)), bind(&on_slide, ref(value), _1));
(it's for connecting Qt signals to functions/functors without going through the extra bother of the moc step at build time).
A comment in this post on my blog has a good generic solution: http://uint32t.blogspot.com/2008/11/using-boost-bind-and-boost-function.html The only issue with it as far as I can see is that it requires exact type matches. Would love to see you take that further :) It essentially mimics what moc would generate. Sohail Signature file gone again.

On 7/5/2010 8:52 PM, Sohail Somani wrote:
On 10-07-05 2:33 PM, Edd Dawson wrote:
A comment in this post on my blog has a good generic solution:
http://uint32t.blogspot.com/2008/11/using-boost-bind-and-boost-function.html
Yep, I'm pretty much at exactly the same stage now that you got to :)
The only issue with it as far as I can see is that it requires exact type matches.
Yeah. I've got an optional check using QMetaObject::checkConnectArgs that the signal/slot parameters do indeed match. I composed the slot signature string using some std::type_info/demangling hackery for the platforms I'm interested in.
Would love to see you take that further :) It essentially mimics what moc would generate.
If you're interested, I could put up a repo? It's functional already, just polishing now... Cheers, Edd

On 10-07-05 4:14 PM, Edd Dawson wrote:
On 7/5/2010 8:52 PM, Sohail Somani wrote:
On 10-07-05 2:33 PM, Edd Dawson wrote:
A comment in this post on my blog has a good generic solution:
http://uint32t.blogspot.com/2008/11/using-boost-bind-and-boost-function.html
Yep, I'm pretty much at exactly the same stage now that you got to :)
Oh, it sounds like you are much farther ahead!
The only issue with it as far as I can see is that it requires exact type matches.
Yeah. I've got an optional check using QMetaObject::checkConnectArgs that the signal/slot parameters do indeed match. I composed the slot signature string using some std::type_info/demangling hackery for the platforms I'm interested in.
Is that necessary? I'm not sure.
Would love to see you take that further :) It essentially mimics what moc would generate.
If you're interested, I could put up a repo? It's functional already, just polishing now...
For sure!

On 7/5/2010 9:39 PM, Sohail Somani wrote:
On 10-07-05 4:14 PM, Edd Dawson wrote:
Yeah. I've got an optional check using QMetaObject::checkConnectArgs that the signal/slot parameters do indeed match. I composed the slot signature string using some std::type_info/demangling hackery for the platforms I'm interested in.
Is that necessary? I'm not sure.
Well, what's to stop you connecting a Qt signal with signature "itemChanged(const QString &)" to something like a function<void (int)> otherwise (and casting a QString* to an int* in the process)?
If you're interested, I could put up a repo? It's functional already, just polishing now...
For sure!
Repo: http://bitbucket.org/edd/sigfwd/src Zip file: http://bitbucket.org/edd/sigfwd/get/tip.zip Hastily written introduction!: http://bitbucket.org/edd/sigfwd/wiki/Home Cheers, Edd

On 10-07-05 5:06 PM, Edd Dawson wrote:
On 7/5/2010 9:39 PM, Sohail Somani wrote:
On 10-07-05 4:14 PM, Edd Dawson wrote:
Yeah. I've got an optional check using QMetaObject::checkConnectArgs that the signal/slot parameters do indeed match. I composed the slot signature string using some std::type_info/demangling hackery for the platforms I'm interested in.
Is that necessary? I'm not sure.
Well, what's to stop you connecting a Qt signal with signature "itemChanged(const QString &)" to something like a function<void (int)> otherwise (and casting a QString* to an int* in the process)?
Oh, whoops, I meant using platform-specific stuff. Just a vector of typeids should be enough? Will take a look at your implementation, thanks!

On 7/5/2010 10:11 PM, Sohail Somani wrote:
On 10-07-05 5:06 PM, Edd Dawson wrote:
On 7/5/2010 9:39 PM, Sohail Somani wrote:
On 10-07-05 4:14 PM, Edd Dawson wrote:
Yeah. I've got an optional check using QMetaObject::checkConnectArgs that the signal/slot parameters do indeed match. I composed the slot signature string using some std::type_info/demangling hackery for the platforms I'm interested in.
Is that necessary? I'm not sure.
Well, what's to stop you connecting a Qt signal with signature "itemChanged(const QString &)" to something like a function<void (int)> otherwise (and casting a QString* to an int* in the process)?
Oh, whoops, I meant using platform-specific stuff. Just a vector of typeids should be enough?
typeid(T).name() is a mangled name on all my g++ based implementations, so I can't generate an accurate call signature for the slot without doing some g++ specific stuff there. Did you manage to do a compatability check some other way? Edd

On 10-07-05 5:27 PM, Edd Dawson wrote:
typeid(T).name() is a mangled name on all my g++ based implementations, so I can't generate an accurate call signature for the slot without doing some g++ specific stuff there.
Did you manage to do a compatability check some other way?
Why not compare the type_info objects? Would that not be sufficient? I haven't looked at your code yet though.

On 7/6/2010 12:21 AM, Sohail Somani wrote:
On 10-07-05 5:27 PM, Edd Dawson wrote:
Did you manage to do a compatability check some other way?
Why not compare the type_info objects?
The Qt signal is specified as a string, so one can't get type_infos for its parameters. I guess it might be possible to pass a pointer to the Qt signal method instead. Is that something you've tried? Cheers, Edd

On 10-07-05 7:45 PM, Edd Dawson wrote:
On 7/6/2010 12:21 AM, Sohail Somani wrote:
On 10-07-05 5:27 PM, Edd Dawson wrote:
Did you manage to do a compatability check some other way?
Why not compare the type_info objects?
The Qt signal is specified as a string, so one can't get type_infos for its parameters.
Oh right, duh. Ignore me. So I guess this compatibility is caught at signal connection time, right?
I guess it might be possible to pass a pointer to the Qt signal method instead. Is that something you've tried?
Nope. You've got the right idea. With overloaded signals, I think it will be a pain. Sohail

On 7/6/2010 1:30 AM, Sohail Somani wrote:
On 10-07-05 7:45 PM, Edd Dawson wrote:
The Qt signal is specified as a string, so one can't get type_infos for its parameters.
Oh right, duh. Ignore me. So I guess this compatibility is caught at signal connection time, right?
Yep.
I guess it might be possible to pass a pointer to the Qt signal method instead. Is that something you've tried?
Nope. You've got the right idea. With overloaded signals, I think it will be a pain.
Agreed! Edd
participants (6)
-
Daniel Walker
-
Edd Dawson
-
Jeffrey Lee Hellrung, Jr.
-
joel falcou
-
Larry Evans
-
Sohail Somani