6

How can I pass member function pointer to std::function through a function. I am going to explain it by comparison (Live Test):

template<class R, class... FArgs, class... Args>
    void easy_bind(std::function<R(FArgs...)> f, Args&&... args){ 
}

int main() {
    fx::easy_bind(&Class::test_function, new Class);
    return 0;
}

I get an error message:

no matching function for call to ‘easy_bind(void (Class::*)(int, float, std::string), Class*)’

I just don't understand why a function pointer cannot be passed to std::function when its being passed through a function parameter. How can I pass that function? I am willing to change the easy_bind function parameter from std::function into a function pointer but I really don't know how.

EDIT: Question simplified.

EDIT: Thanks to @remyabel, I was able to get what I needed: http://ideone.com/FtkVBg

template <typename R, typename T, typename... FArgs, typename... Args>
auto easy_bind(R (T::*mf)(FArgs...), Args&&... args)
-> decltype(fx::easy_bind(std::function<R(T*,FArgs...)>(mf), args...)) {
    return fx::easy_bind(std::function<R(T*,FArgs...)>(mf), args...);
}
Gasim
  • 7,615
  • 14
  • 64
  • 131
  • I'm researching a work-around, so my answer is incomplete at the moment. [Generic functor for functions with any argument list](https://stackoverflow.com/questions/9050047/generic-functor-for-functions-with-any-argument-list) seems like a good candidate, but that doesn't take into account member function pointers. –  Jan 22 '14 at 00:50
  • What types would you expect for `R`, `FArgs`, and `Args`? – Ben Voigt Jan 22 '14 at 00:57
  • I got this `easy_bind` working with global functions: http://ideone.com/FtkVBg. But member functions still fail to work :( – Gasim Jan 22 '14 at 01:02
  • @BenVoigt `R(FArgs...)` is a function, in my case its the type of `&Class::test_function`; and the `Args` is the type of `new Class` – Gasim Jan 22 '14 at 01:04
  • @Gasim I edited my answer, however I am derping hard and cannot figure out how to eliminate the need to pass a useless object to the function call. Perhaps someone can take a look. Edit: Scratch that, it works as intended. –  Jan 22 '14 at 01:04

2 Answers2

18

http://en.cppreference.com/w/cpp/utility/functional/mem_fn is what you are supposed to use

struct Mem
{
    void MemFn() {}
};

std::function<void(Mem*)> m = std::mem_fn(&Mem::MemFn);
ACB
  • 1,607
  • 11
  • 31
  • what is the advantage of it over `m = &Mem::MemFn` – Gasim Jan 22 '14 at 01:29
  • 1
    it compiles! because std::mem_fn will construct a function object that takes a Mem* as its first arg when called and &Mem::MemFn will return a void (__thiscall Mem::* const &)(void) – ACB Jan 22 '14 at 01:37
  • well you can still use your answer to get some template magic done like op did in the end so i wouldnt say its pointless. – ACB Jan 22 '14 at 01:44
  • @ACB Yeah, `auto func3 = fx::easy_bind(std::mem_fn(&SomeStruct::function), new SomeStruct);` doesn't compile. Your answer could be improved (and possibly accepted instead of mine) if you figure out how to get it working. I assumed that I was simply reinventing `mem_fn`, but I guess they're not identical. –  Jan 22 '14 at 01:51
  • @ACB http://ideone.com/lYd5DQ they both seem to compile for me... I never really understood the point of mem_fn. I think std::function wraps a member function pointer around mem_fn when passing, but thats just a thought – Gasim Jan 22 '14 at 02:24
  • After researching, I found out that `mem_fn` is like a tiny version of bind. – Gasim Jan 22 '14 at 02:32
  • atleast in visual studio 2013 &Mem::MemFn gives you 1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(506): error C2664: 'void std::_Func_class<_Ret,Mem *>::_Set(std::_Func_base<_Ret,Mem *> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,Mem *> *' – ACB Jan 22 '14 at 10:42
  • i will need to recompile the whole thing with msvc after being done making it work with gcc. – Gasim Jan 23 '14 at 04:46
3

I think the problem can be narrowed down to this:

template<class R, class... FArgs>
void test(std::function<R(FArgs...)> f)
{
}

int main() {
  test(&SomeStruct::function);
}

The error message is pretty similar without the rest of the easy_bind stuff:

main.cpp: In function 'int main()':
main.cpp:63:31: error: no matching function for call to 
'test(void (SomeStruct::*)(int, float, std::string))'
     test(&SomeStruct::function);
main.cpp:63:31: note: candidate is:
main.cpp:49:10: note: template<class R, class ... FArgs> 
void test(std::function<_Res(_ArgTypes ...)>)
     void test(std::function<R(FArgs...)> f)
          ^
main.cpp:49:10: note:   template argument deduction/substitution failed:
main.cpp:63:31: note:   'void (SomeStruct::*)(int, float, std::string) 
{aka void (SomeStruct::*)(int, float, std::basic_string<char>)}' 
is not derived from 'std::function<_Res(_ArgTypes ...)>'
     test(&SomeStruct::function);

Essentially, it can't magically create an std::function for you. You need something like your Functor alias.


So thanks to the answer provided in generic member function pointer as a template parameter, here's what you can do:

//Test Case:
struct SomeStruct {
public:
 int function(int x, float y, std::string str) {
   std::cout << x << " " << y << " " << str << std::endl;
   return 42;
 }
};

template <typename Ret, typename Struct, typename ...Args>
std::function<Ret (Struct*,Args...)> proxycall(Ret (Struct::*mf)(Args...))
{
    return std::function<Ret (Struct*,Args...)>(mf);
}

int main() {
    auto func3 = fx::easy_bind(proxycall(&SomeStruct::function), new SomeStruct);
    int ret = func3(5, 2.5, "Test3");
    std::cout << ret << "\n";

    return 0;
}

Now it works automatically.

Live Example

Community
  • 1
  • 1