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

How do i write a pointer-to-member-function with std::function?

本文关键字:函数 成员 指针 何用 std      更新时间:2023-10-16

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

如果您想编译/测试,请使用伪代码

-编辑-根据答案,我想我只需要使用typedef,而不需要使用std::函数

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

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

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

要将实例绑定到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

Scott Meyer的《现代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是非常数)。

您可以使用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;
}

如果你可以使用Boost,那么你就可以使用Boost.Bind

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

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