Before diving into fixing your binder, a few notes:
- You don't really need to use
std::mem_fn()
for the first argument of std::bind()
as std::bind()
already knows how to deal with member function pointers.
- The type of taking an address of a member function is undefined. That is, you can't really on
std::string::push_back
being a member function pointer taking just one argument.
- Instead of using
std::ref(testobj)
you could jut juse &testobj
.
You can't deduce a member function like this if it needs to have argument: you'll need to specify the argument:
template <class T, typename RETURN_TYPE, typename...Args, typename... Arguments>
std::function<RETURN_TYPE(Arguments...)>
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params) {
...
}
This gets you over the immediate error. The next problem is that you somehow related the bound arguments to the type of function being called. Of course, that's not how it works. In your case, the resulting argument actually doesn't take any arguments, i.e., you'd have a declaration like this:
template <class T, typename RETURN_TYPE, typename... Args, typename... Arguments>
std::function<RETURN_TYPE()>
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params) {
...
}
In case you actually use a placeholder with your function, the returned std::function<RC(...)>
would actually take some argument. Figuring these arguments out is somewhat non-trivial. When restricting the argument type to a pointer to function or a pointer to member function it should be doable to return an appropriate function object, though.
Just for the fun of it, here is an implementation which seems to deal with placeholders (it isn't thoroughly tested, though):
#include <functional>
#include <iostream>
#include <string>
using namespace std::placeholders;
struct foo
{
void f(int i, double d, char c) {
std::cout << "f(int=" << i << ", double=" << d << ", char=" << c << ")\n";
}
};
template <typename...> struct type_list;
template <typename, typename, typename, typename> struct objbind_result_type;
template <typename RC, typename... RA>
struct objbind_result_type<RC, type_list<RA...>, type_list<>, type_list<> > {
typedef std::function<RC(RA...)> type;
};
template <typename RC,
typename... RA,
typename A0, typename... A,
typename B0, typename... B>
struct objbind_result_type<RC, type_list<RA...>,
type_list<A0, A...>,
type_list<B0, B...> >;
template <bool, typename, typename, typename, typename, typename>
struct objbind_result_type_helper;
template <typename A0, typename RC, typename... RA, typename... A, typename...B>
struct objbind_result_type_helper<true, A0, RC, type_list<RA...>, type_list<A...>, type_list<B...> > {
typedef typename objbind_result_type<RC, type_list<RA..., A0>, type_list<A...>, type_list<B...> >::type type;
};
template <typename A0, typename RC, typename... RA, typename... A, typename...B>
struct objbind_result_type_helper<false, A0, RC, type_list<RA...>, type_list<A...>, type_list<B...> > {
typedef typename objbind_result_type<RC, type_list<RA...>, type_list<A...>, type_list<B...> >::type type;
};
template <typename RC,
typename... RA,
typename A0, typename... A,
typename B0, typename... B>
struct objbind_result_type<RC, type_list<RA...>,
type_list<A0, A...>,
type_list<B0, B...> > {
typedef typename objbind_result_type_helper<bool(std::is_placeholder<B0>::value), A0,
RC, type_list<RA...>,
type_list<A...>,
type_list<B...> >::type type;
};
// This is the function I'd like to have working:
template <class T, typename RETURN_TYPE, typename...Args, typename... Arguments>
typename objbind_result_type<RETURN_TYPE, type_list<>, type_list<Args...>, type_list<Arguments...> >::type
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params)
{
return std::bind(in_fun, &obj, params...);
}
int main()
{
foo fo;
auto fun = obj_bind(&foo::f, fo, _1, 2.34, _2);
fun(17, 'b');
}