如何用std :: function编写指向成员函数的指针?

时间:2012-02-14 17:12:50

标签: c++

我知道如何在std :: function(int fn(double))中声明std::function<int(double)>。我知道如何编写指向成员的函数(typedef int (A::*MemFn)(double d);)。但是我如何用std :: function编写指向成员函数的函数?

虚拟代码,如果您想编译/测试

-edit-基于答案我认为我只会使用typedef而不是打扰std :: function

#include <cstdio>
#include <functional>

struct A{ int fn(double){ return 0; } };
int fn2(double){ return 0; }

typedef int (A::*MemFn)(double d);
typedef std::function<int(double)> MemFn2;

void Test(A*a, MemFn2 fn){
    fn(1.2f);
}
void Test(A*a, MemFn fn){
    (a->*fn)(1.2f);
}

int main(){
    Test(new A, &A::fn);
    Test(new A, &fn2);
}

5 个答案:

答案 0 :(得分:26)

std::function完全能够直接存储成员函数指针。但是,您必须适当调整参数列表。必须使用类型(或派生类型)的实例调用成员指针。将它们放在std::function中时,参数列表中的第一个参数应该是对象类型的指针(或引用或智能指针)。

所以,如果我有以下课程:

struct Type
{
public:
    int Foo();
};

std::function中存储此成员函数的正确语法是:

std::function<int(Type&)> fooCaller = &Type::Foo;

如果要保留参数列表(在您的情况下为int(double)),则需要在function之外提供实例。这可以通过std::bind

完成
struct A{ int fn(double){ return 0; } };

A anInstance;
std::function<int(double)> fnCaller = std::bind(&A::fn, &anInstance, std::placeholders::_1);

请注意,您的责任确保只要std::bind处于活动状态,您提供给fnCaller的对象指针就会保持活动状态。如果你向某人返回fnCaller,并且它有一个指向堆栈对象的指针,那你就麻烦了。

可以将shared_ptr(或任何可复制的智能指针)绑定为对象,这要归功于函数调用机制的定义:

struct A{ int fn(double){ return 0; } };

auto anInstance = std::make_shared<A>();
std::function<int(double)> fnCaller = std::bind(&A::fn, anInstance, std::placeholders::_1);

现在你不必担心;绑定器将继续保持对象存活,因为它按值存储shared_ptr

答案 1 :(得分:9)

成员函数不是函数。它本身并不是你可以称之为的东西。您所能做的就是调用实例对象的成员函数。只有一对指向成员函数的指针对象构成一个可调用的实体。

要将实例绑定到PTMF并获取可调用的内容,请使用bind

#include <functional>

struct Foo
{
    double bar(bool, char);
};

Foo x;
using namespace std::placeholders;
std::function<double(bool, char)> f = std::bind(&Foo::bar, x, _1, _2);
f(true, 'a'); //...

与lambdas一样,绑定表达式具有不可知的类型,转换为std::function(以及实际的调度)可能很昂贵。如果可能,最好使用auto作为绑定表达式的类型。

答案 2 :(得分:5)

Scott Meyer的Modern C ++ 11书中的一个指导原则是避免使用std::bind并始终使用lambda闭包:

struct A{ int fn(double){ return 0; } };

std::function<int(double)> f = [a = A{}](double x) mutable { return a.fn(x); };

此处需要mutable,因为函数调用可能会更改捕获a(因为A::fn是非常量的)。

答案 3 :(得分:0)

您可以使用std::binder1st将成员函数绑定到类实例:

typedef std::binder1st<std::mem_fun1_t<int, A, double>> MemFn;

void Test(A* a, double d)
{
   MemFn fn(std::mem_fun(&A::fn), a);
   int nRetVal = fn(d);
}

int main()
{
   Test(new A, 1.2f);
   return 0;
}

答案 4 :(得分:0)

如果您可以使用Boost,则可以使用Boost.Bind。这很容易实现:

boost::bind(&MyClass::MemberFunction, pInstance, _1, _2)

希望它是相当不言自明的。 _1_2是您可以传递给函数的参数的占位符。