如何将函子分配给函数指针?

时间:2014-05-21 23:11:47

标签: c++ winapi functional-programming function-pointers functor

通常,我可以将函数对象分配给函数指针吗?我想做这样的事情:

#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
}

如果那是不可能的,我想要一个专门针对Windows编程的替代方案,我希望WindowProc包含从WinMain的正文数据设置的状态信息(即没有制作全局变量)。分配给WNDCLASSEX的{​​{1}}成员时会出现此问题。虽然lpfnWndProc解决了上述代码段的问题:

std::function

它对我的WinAPI案例不起作用:

std::function<void(int)> sf = f;
sf(2); // prints 84

MSVC 2013错误:

1。)错误C2440: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 } :无法从=转换为WindowProc

2。)错误C3867:WNDPROC:函数调用缺少参数列表;使用WindowProc::operator ()创建指向成员的指针

2续。)错误C2440:&WindowProc::operator ():无法从=转换为LRESULT (__stdcall WindowProc::* )(HWND,UINT,WPARAM,LPARAM)

3。)与&#39; 2续。&#39;

相同

4.。)错误C2440:WNDPROC:无法从=转换为std::function<baz>

5.)与4相同。

我怎样才能让它发挥作用?

2 个答案:

答案 0 :(得分:2)

通常,除了要调用的函数之外,函数对象还包含其他上下文信息。关于可以分配给函数指针的唯一函数对象是带有空捕获的lambda函数,但这实际上只是一个函数:

void (*bar)(int) = [](int x) { std::cout << x; }

如果你想通过函数指针获取一个函数对象,你需要希望函数指针有一个合适的参数,供用户指定,哪些可以直接传递:

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);

最合理的现代接口采用函数指针也采用用户数据指针,可用于传递必要的上下文。显然,除了通过必要的上下文之外,可能还需要以某种方式维护用作上下文的对象的生命周期。

我不是Windows程序员,但我猜你正在尝试使用的API实际上能够设置函数指针和指向某些用户数据的指针。如果没有地方可以传递上下文信息,则需要以某种方式在函数指针本身中编码必要的信息。例如,您可以使用引用全局对象的函数指针来获取上下文。显然,您需要为要传递的每个上下文使用不同的函数。

答案 1 :(得分:1)

您需要以通常的方式声明指向成员函数的指针,然后调用它。试试这个:

#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
}

您必须通过实例化来调用它,在此示例中为f