C++ 在一个类中使用成员函数的泛型std::function对象

C++ 在一个类中使用成员函数的泛型std::function对象,c++,function,function-pointers,c++11,tr1,C++,Function,Function Pointers,C++11,Tr1,对于一个类,我想在一个map存储std::function对象中存储一些指向同一类的成员函数的函数指针。但我一开始就失败了,代码如下: #include <functional> class Foo { public: void doSomething() {} void bindFunction() { // ERROR std::function<void(void)> f =

对于一个类,我想在一个
map
存储
std::function
对象中存储一些指向同一类的成员函数的函数指针。但我一开始就失败了,代码如下:

#include <functional>

class Foo {
    public:
        void doSomething() {}
        void bindFunction() {
            // ERROR
            std::function<void(void)> f = &Foo::doSomething;
        }
};
#包括
福班{
公众:
void doSomething(){}
void bindFunction(){
//错误
std::function f=&Foo::doSomething;
}
};
我收到
错误C2064:term未计算为在
xxcallobj
中包含0个参数的函数,并伴有一些奇怪的模板实例化错误。目前,我正在使用VisualStudio2010/2011开发Windows8,使用VS10开发Win7,但也失败了。这个错误必须基于一些奇怪的C++规则,我不遵守

< p>或者你需要< /p>
std::function<void(Foo*)> f = &Foo::doSomething;

必须使用对象调用非静态成员函数。也就是说,它总是隐式地传递“this”指针作为其参数

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
由于您的
std::function
签名指定您的函数不接受任何参数(
),因此必须绑定第一个(也是唯一一个)参数

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
std::function f=std::bind(&Foo::doSomething,this);
如果要使用参数绑定函数,则需要指定占位符:

using namespace std::placeholders;
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, std::placeholders::_1, std::placeholders::_2);
使用名称空间std::占位符;
std::function f=std::bind(&Foo::doSomethingArgs,this,std::占位符::_1,std::占位符::_2);
或者,如果编译器支持C++11 lambdas:

std::function<void(int,int)> f = [=](int a, int b) {
    this->doSomethingArgs(a, b);
}
std::函数f=[=](int a,int b){
这->doSomethingArgs(a,b);
}

(我手头没有支持C++11的编译器,因此无法检查此编译器。)

如果需要在不存储类实例的情况下存储成员函数,可以执行以下操作:

class MyClass
{
public:
    void MemberFunc(int value)
    {
      //do something
    }
};

// Store member function binding
auto callable = std::mem_fn(&MyClass::MemberFunc);

// Call with late supplied 'this'
MyClass myInst;
callable(&myInst, 123);
std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable
如果没有auto,存储类型会是什么样子? 大概是这样的:

class MyClass
{
public:
    void MemberFunc(int value)
    {
      //do something
    }
};

// Store member function binding
auto callable = std::mem_fn(&MyClass::MemberFunc);

// Call with late supplied 'this'
MyClass myInst;
callable(&myInst, 123);
std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable
std::\u Mem\u fn\u wrap可调用
还可以将此函数存储传递给标准函数绑定

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1);
binding(123); // Call
std::function binding=std::bind(可调用,&testA,std::占位符::_1);
有约束力(123);//呼叫

过去和将来的注意事项:存在一个较旧的接口std::mem_func,但后来被弃用。在C++17之后,有一个提议要提出。这将是非常受欢迎的。

如果您希望在引擎盖下使用不太通用且更精确的控制,可以使用函子。使用win32 api将api消息从一个类转发到另一个类的示例

IListener.h

祝大家好运,感谢大家分享知识。

< P>不幸的是,C++不允许你直接获得一个对象和一个成员函数的可调用对象。code>&Foo::doSomething
为您提供了一个“指向成员函数的指针”,它引用的是成员函数,而不是关联的对象

有两种方法,一种是使用
std::bind
将“指向成员函数的指针”绑定到
this
指针。另一种方法是使用lambda捕获
this
指针并调用成员函数

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
std::function<void(void)> g = [this](){doSomething();};
std::function f=std::bind(&Foo::doSomething,this);
函数g=[this](){doSomething();};
我更喜欢后者

使用g++时,至少将一个成员函数绑定到该函数将导致对象大小为三个指针,将其分配给
std::function
将导致动态内存分配

另一方面,捕获
的lambda大小仅为一个指针,将其分配给
std::function
不会导致使用g++进行动态内存分配


虽然我还没有与其他编译器验证过这一点,但我怀疑会在那里找到类似的结果。

您可以避免
std::bind
这样做:

std::function f=[this]->{Foo::doSomething();}

由于我不依赖boost,因此我将使用lambda表达式;)不过谢谢@AlxB: Boo..Bin不使用占位符的ADL,它将它们放在匿名命名空间中。我建议避免全局捕获[],并使用[S]来明确捕获的内容(Scott Meyers -有效的现代C++第6章。第31条-避免默认捕获模式)只需添加一点提示:成员函数指针可以隐式转换为
std::function
,并将额外的
this
作为第一个参数,如
std::function=&Foo::doSomethingArgs
@landerYoung:添加函数名,如上面的“f”,以修复示例语法。如果您不需要名称,可以使用mem_fn(&Foo::doSomethingArgs)。@Danh
std::mem_fn
未删除;一堆不必要的重载被删除了。另一方面,
std::mem_-fun
被C++11弃用,将被C++17删除。@Danh这正是我要说的;)第一个“基本”重载仍然存在:
template unspecified mem_fn(rt:*),它不会消失。@Danh仔细阅读。博士删除了13个重载中的12个。最后一个重载不是(也不会是;在C++11或C++14中都不是)。为什么投反对票?其他每个响应都说必须绑定类实例。如果要为反射或脚本创建绑定系统,则不希望这样做。这个替代方法对某些人来说是有效的和相关的。谢谢Danh,我编辑了一些关于过去和未来相关接口的评论。谢谢你给出了这个很棒的答案:D正是我所需要的,我找不到如何专门化std::函数来调用任何类实例上的成员函数。这是编译的,但它是标准的吗?你保证第一个参数是
这个
?@sudorm rfslash是的,谢谢你的回复@ArmenTsirunyan。。。我可以在标准中的何处查找此信息?
class Button {
    public:
    Dispatcher _dispatcher;
    //button window forward all received message to a listener
    LRESULT onMessage(HWND hWnd, UINT uMsg, WPARAM w, LPARAM l) {
        //to return a precise message like WM_CREATE, you have just
        //search it in the map.
        return _dispatcher[uMsg](hWnd, uMsg, w, l);
    }
};

class Myclass {
    Button _button;
    //the listener for Button messages
    LRESULT button_listener(HWND hWnd, UINT uMsg, WPARAM w, LPARAM l) {
        return 0;
    }

    //Register the listener for Button messages
    void initialize() {
        //now all message received from button are forwarded to button_listener function 
       _button._dispatcher.add(WM_CREATE, this, &Myclass::button_listener);
    }
};
std::function<void(void)> f = std::bind(&Foo::doSomething, this);
std::function<void(void)> g = [this](){doSomething();};