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

29 c++

我知道如何int fn(double)在std :: function(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);
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 26

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

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

struct Type
{
public:
    int Foo();
};
Run Code Online (Sandbox Code Playgroud)

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

std::function<int(Type&)> fooCaller = &Type::Foo;
Run Code Online (Sandbox Code Playgroud)

如果你想保留参数列表(在你的情况下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);
Run Code Online (Sandbox Code Playgroud)

请注意,您有责任确保您提供的对象指针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);
Run Code Online (Sandbox Code Playgroud)

现在你不必担心; 绑定器将继续保持对象存活,因为它存储了一个shared_ptrby值.

  • @Nawaz:你在编译器中试过了吗?[它有效.](http://ideone.com/LKSZD)该规范说它有效.我不能真正引用这个规范,因为这个东西的定义分散在20.8节的大约4个部分,但要密切关注20.8.2和20.8.11. (3认同)

Ker*_* SB 10

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

要将实例绑定到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'); //...
Run Code Online (Sandbox Code Playgroud)

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


dav*_*igh 6

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

mutable是必要的,因为a函数调用可能会改变捕获(因为A::fn它是非const).