I am trying to write a metafunction named signature_of which, given the type of a function (pointer), functor, or lambda, returns its signature.
Here's what I have so far:
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <type_traits>
template <typename F>
struct signature_of_member
{
typedef typename boost::function_types::result_type<F>::type result_type;
typedef typename boost::function_types::parameter_types<F>::type parameter_types;
typedef typename boost::mpl::pop_front<parameter_types>::type base;
typedef typename boost::mpl::push_front<base, result_type>::type L;
typedef typename boost::function_types::function_type<L>::type type;
};
template <typename F, bool is_class>
struct signature_of_impl
{
typedef typename boost::function_types::function_type<F>::type type;
};
template <typename F>
struct signature_of_impl<F, true>
{
typedef typename signature_of_member<decltype(&F::operator())>::type type;
};
template <typename F>
struct signature_of
{
typedef typename signature_of_impl<F, std::is_class<F>::value>::type type;
};
It's pretty straightforward, with most of the real work being done by the boost::function_types library. The general idea is:
This works for built-in functions:
int f(int);
typedef signature_of<decltype(f)>::type Sig; // Sig is int(int)
for lambdas:
auto f = [](int) { return 0; }
typedef signature_of<decltype(f)>::type Sig; // Sig is int(int)
and for functors:
struct A
{
int operator()(int);
};
typedef signature_of<A>::type Sig; // Sig is int(int)
However, it doesn't work for bind() expressions (which are a special case of functors). If I try this:
#include <functional>
int g(int);
typedef signature_of<decltype(std::bind(g, 0))>::type Sig;
I get a compiler error:
In file included from test.cpp:3:0:
signature_of.hpp: In instantiation of 'signature_of_impl<
_Bind<int (*(int))(int)>, true
>':
signature_of.hpp:45:74: instantiated from 'signature_of<
_Bind<int (*(int))(int)>
>'
test.cpp:21:52: instantiated from here
signature_of.hpp:39:74: error: type of '& _Bind<
int (*)(int)({int} ...)
>::operator()' is unknown
The problem is that the operator() of the functor returned by bind() is a template, and so its type cannot be determined.
Is it possible to get the signature of a bind() expression another way?
std::bind is for partial function application. That is, suppose you have a function object f which takes 3 arguments: f(a,b,c); You want a new function object which only takes two arguments, defined as: g(a,b) := f(a, 4, b);
Internally, std::bind() detects that a pointer to a member function is passed and most likely turns it into a callable objects, e.g., by use std::mem_fn() with its first argument.
boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions.
The std::invoke() method can be used to call functions, function pointers, and member pointers with the same syntax: #include <iostream>#include <functional>using namespace std;void globalFunction( ) { cout << "globalFunction ..." <<
You've got more problems than the fact that a binder's operator() is templated, it also has an arbitrary count of parameters. Remember that you're supposed to be able to invoke the result of bind with any number of extra arguments. For example:
int f(int);
auto bound = boost::bind(f, _2);
bound
may now be called with any number of arguments of 2 or more, only the second is actually forwarded on to the function.
So basically, as another answer said, this object has no signature. It's signature is defined only by how it is used.
If the operator is templated, then it doesn't have a signature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With