问题
Generally, can I assign a function object to a function pointer? I want to do something like this:
#include <iostream>
class Foo {
int num;
public:
Foo(int num_par) : num(num_par) {}
void operator()(int multiplier) {
std::cout << multiplier * num << std::endl;
}
};
int main() {
typedef void(*bar)(int);
Foo f(42);
bar b = f; // MSVC error
// ^ C2440: 'initializing' : cannot convert from 'Foo' to 'bar'
b(2); // wanted to print 84
}
If that's impossible, I’d like an alternative specifically for Windows programming, where I want WindowProc
to contain state information that is set from data local to WinMain
’s body (i.e. without making global variables). The problem occurs when assigning to the WNDCLASSEX
’s lpfnWndProc
member. Though std::function
solves the problem for the above snippet:
std::function<void(int)> sf = f;
sf(2); // prints 84
it doesn't work for my WinAPI case:
class WindowProc {
int some_state;
public:
void set_some_state(int par);
LRESULT CALLBACK operator()(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow) {
HWND hWnd;
WNDCLASSEX wc;
WindowProc wp;
typedef LRESULT(CALLBACK *baz)(HWND, UINT, WPARAM, LPARAM);
std::function<baz> std_func = wp;
std::function<baz> std_binded_func = std::bind(&WindowProc::operator(), &wp);
// none of these compile:
wc.lpfnWndProc = wp; // #1
wc.lpfnWndProc = wp.operator(); // #2
wc.lpfnWndProc = &WindowProc::operator(); // #3. Wrong anyway because some_state's value is part of the instance, not the class
wc.lpfnWndProc = std_func; // #4. Wrong anyway because some_state's value is part of the instance, not the class
wc.lpfnWndProc = std_binded_func; // #5
// do stuff...
wp.set_some_state(some_runtime_number);
// ...do other stuff
}
MSVC 2013 Errors:
1.) error C2440: =
: cannot convert from WindowProc
to WNDPROC
2.) error C3867: WindowProc::operator ()
: function call missing argument list; use &WindowProc::operator ()
to create a pointer to member
2 cont.) error C2440: =
: cannot convert from LRESULT (__stdcall WindowProc::* )(HWND,UINT,WPARAM,LPARAM)
to WNDPROC
3.) same as '2 cont.'
4.) error C2440: =
: cannot convert from std::function<baz>
to WNDPROC
5.) same as 4.
How can I get it to work?
回答1:
In general, function objects contain additional context information besides the function to be called. About the only function object you can assigned to a function pointer is a lambda function with an empty capture but this is really just a function:
void (*bar)(int) = [](int x) { std::cout << x; }
If you want to get a function object through a function pointer, you need to hope that the function pointer has a suitable argument which is available for users to specify and which can passed through directly:
void call_function(int arg, void* user_data) {
(*static_cast<std::function<void(int)>*>(userdata))(arg);
}
...
std::function<void(int)> function_object;
void (*bar)(int, void*) = &call_function;
bar(17, &function_object);
Most reasonably modern interfaces taking a function pointer also take a user-data pointer which can be used to pass through the necessary context. Obviously, in addition to passing through the necessary context it may be necessary to somehow maintain the life-time of object used as context.
I'm not a Windows programmer but I would guess that the API you are trying to use actually has the ability to set both a function pointer and a pointer to some user data. If there is no place to pass through context information you would need to somehow encode the necessary information in the function pointer itself. For example, you could use a function pointer which references a global object to get the context. Clearly, you would need a different function for each context you want to pass.
回答2:
You need to declare a pointer to a member function, in the usual way, then invoke it. Try this:
#include <iostream>
class Foo {
int num;
public:
Foo(int num_par) : num(num_par) {}
void operator()(int multiplier) {
std::cout << multiplier * num << std::endl;
}
};
int main() {
typedef void(Foo::*bar)(int);
Foo f(42);
bar b = &Foo::operator(); // no more MSVC error
// ^ C2440: 'initializing' : cannot convert from 'Foo' to 'bar'
(f.*b)(2); // wanted to print 84, and it does
}
You have to call it through an instantiation, in this example f
.
来源:https://stackoverflow.com/questions/23795348/how-to-assign-functor-to-function-pointer