13

Here is a code:

#include <functional>
using namespace std::tr1;

typedef void(*fp)(void);

void foo(void)
{

}

void f(fp)
{

}

int main()
{
  function<void(void)> fun = foo;
  f(fun); // error
  f(foo); // ok
}

Originally i need to make a function pointer from non-static class method because i need to save data between function callings. I tried std::tr1::bind and boost::bind, but they return functional object, not pointer, which, as i can see, can't be "casted" to pure functional pointer. While the function signature (SetupIterateCabinet) demands a pure func pointer exactly.

I need an advise how to solve the problem. Thank you.

fogbit
  • 1,961
  • 6
  • 27
  • 41
  • 1
    See also [c++ - How do I pass a std::function object to a function taking a function pointer? - Stack Overflow](https://stackoverflow.com/questions/39562437/how-do-i-pass-a-stdfunction-object-to-a-function-taking-a-function-pointer) (although it's more general than this question) – user202729 Jan 20 '21 at 04:24

2 Answers2

8

You can't convert a std::function to a function pointer(you can do the opposite). You should use either function pointers, or std::functions. If you can use std::function instead of pointers, then you should.

This makes your code work:

typedef function<void(void)> fp;
mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • The only thing I'll add is that using std::function also allows you to use a type with operator () overloaded. Excellent answer. – Stephen Newell May 11 '12 at 16:52
  • 4
    How do you propose he change `SetupIterateCabinet` (a C API) to take a C++ object? – ildjarn May 11 '12 at 16:53
  • @ildjarn "You should use either function pointers, or `std::function`". If he can't use `std::function` then he ought to use function pointers, unless he wants to wrap his `std::function`s around static functions, but that's not going to be pretty. – mfontanini May 11 '12 at 16:57
  • @ildjarn you can't and he didn't state anything else. In those cases I usually have a wrapper plain C function that, using the "user context" most often passed to callbacks (SetupIterateCabinet offers one as well) to route the callback to some C++ thing. – zerm May 11 '12 at 16:59
  • 1
    @fontanini: So, there is no way to pass object having state? – fogbit May 11 '12 at 17:00
  • @zerm : Exactly my point, and the point this answer entirely misses. – ildjarn May 11 '12 at 17:02
  • I thought `SetupIterateCabinet` was a function OP had created, I didn't know it was a Windows API function, nor did I know that you could pass a "context" parameter. – mfontanini May 11 '12 at 17:04
  • @ildjarn yes, but it was more a fault of the OP, so I felt that downvote was not justified. Good thing you've already provided an answers better matching OP's intend, though ;) – zerm May 11 '12 at 17:13
  • @zerm : If the OP hadn't specifically mentioned `SetupIterateCabinet` then I agree that the downvote wouldn't be justified. As it is... – ildjarn May 11 '12 at 17:16
7

You've greatly oversimplified your real problem and turned your question into an XY problem. Let's get back to your real question: how to call SetupIterateCabinet with a non-static member function as a callback.

Given some class:

class MyClass
{
public:
    UINT MyCallback(UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
    {
        /* impl */
    }
};

In order to use MyClass::MyCallback as the third argument to SetupIterateCabinet, you need to pass a MyClass* for the Context argument and use a plain shim function to take that Context argument and do the right thing with it:

UINT MyClassCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
{
    return static_cast<MyClass*>(Context)->MyCallback(Notification, Param1, Param2);
}

int main()
{
    MyClass mc;
    SetupIterateCabinet(_T("some path"), 0, MyClassCallback, &mc);
}
Community
  • 1
  • 1
ildjarn
  • 62,044
  • 9
  • 127
  • 211