我知道如何在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);
}
答案 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
是您可以传递给函数的参数的占位符。