在一个类中使用带有成员函数的通用std :: function对象

Chr*_*vic 147 c++ function-pointers function tr1 c++11

对于一个类,我想在一个map存储std::function对象中存储一些函数指针到同一个类的成员函数.但是我在这个代码的开头就失败了:

class Foo {
    public:
        void doSomething() {}
        void bindFunction() {
            // ERROR
            std::function<void(void)> f = &Foo::doSomething;
        }
};
Run Code Online (Sandbox Code Playgroud)

我收到error C2064: term does not evaluate to a function taking 0 argumentsxxcallobj一些奇怪的模板实例化的错误结合.目前我正在使用Visual Studio 2010/2011在Windows 8上工作,在使用VS10的Win 7上工作也失败了.错误必须基于我不遵循的一些奇怪的C++规则.

编辑:我使用提升.这是集成在MS编译器中的C++ 11.

Ale*_*x B 266

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

因为您的std::function签名指定您的函数不接受任何参数(<void(void)>),所以必须绑定第一个(也是唯一的)参数.

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
Run Code Online (Sandbox Code Playgroud)

如果要使用参数绑定函数,则需要指定占位符:

using namespace std::placeholders;
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, _1, _2);
Run Code Online (Sandbox Code Playgroud)

或者,如果您的编译器支持C++ 11 lambda:

std::function<void(int,int)> f = [=](int a, int b) {
    this->doSomethingArgs(a, b);
}
Run Code Online (Sandbox Code Playgroud)

(我不手边有一个C++ 11能够编译器现在,所以我不能检查这一项.)

  • 我建议避免全局捕获[=]并使用[this]使捕获的内容更清晰(Scott Meyers - Effective Modern C++ Chapter 6. item 31 - 避免默认捕获模式) (42认同)
  • 只需添加一点提示:成员函数指针可以隐式转换为 `std::function`,并使用额外的 `this` 作为第一个参数,例如 `std::function&lt;void(Foo*, int, int)&gt; = &amp;Foo ::doSomethingArgs` (6认同)
  • @AlexB:Boost.Bind不使用ADL作为占位符,它将它们放在匿名命名空间中. (3认同)

Arm*_*yan 69

要么你需要

std::function<void(Foo*)> f = &Foo::doSomething;
Run Code Online (Sandbox Code Playgroud)

例如,您可以在任何实例上调用它,或者您需要绑定特定实例 this

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 12

如果您需要存储没有类实例的成员函数,您可以执行以下操作:

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);
Run Code Online (Sandbox Code Playgroud)

没有自动存储类型会是什么样子?像这样的东西:

std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable
Run Code Online (Sandbox Code Playgroud)

您还可以将此功能存储传递给标准功能绑定

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1);
binding(123); // Call
Run Code Online (Sandbox Code Playgroud)

过去和将来的注释:旧的界面std :: mem_func已存在,但此后已被弃用.在C++ 17之后存在一个提议,使得指向成员函数的指针可以调用.这将是最受欢迎的.


plu*_*ash 8

不幸的是,C++ 不允许您直接获取引用对象及其成员函数之一的可调用对象。&Foo::doSomething给你一个“指向成员函数的指针”,它指的是成员函数而不是关联的对象。

有两种方法可以解决这个问题,一种是使用std::bind将“指向成员函数的this指针”绑定到指针。另一种是使用一个 lambda 来捕获this指针并调用成员函数。

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
std::function<void(void)> g = [this](){doSomething();};
Run Code Online (Sandbox Code Playgroud)

我更喜欢后者。

使用 g++ 至少将成员函数绑定到 this 将导致对象大小为三指针,将 this 分配给 anstd::function将导致动态内存分配。

另一方面,捕获的 lambdathis大小只有一个指针,将其分配给 anstd::function不会导致使用 g++ 进行动态内存分配。

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


agg*_*sol 8

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

std::function<void(void)> f = [this]-> {Foo::doSomething();}
Run Code Online (Sandbox Code Playgroud)