在 Bjarne Stroustrup 的主页(C++11 FAQ)中:
struct X { int foo(int); };
std::function<int(X*, int)> f;
f = &X::foo; //pointer to member
X x;
int v = f(&x, 5); //call X::foo() for x with 5
它是如何工作的? std :: function 如何调用 foo成员函数?
模板参数是int(X*, int)
,是&X::foo
从成员函数指针转换为非成员函数指针?!
(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))
澄清:我知道我们不需要使用任何指针来使用 std :: function ,但我不知道 std :: function <的内部结构如何/ em>处理成员函数指针和非成员函数指针之间的这种不兼容性。我不知道标准如何允许我们实现像 std :: function !
这样的东西答案 0 :(得分:34)
在获得其他答案和评论的帮助,并阅读GCC源代码和C ++ 11标准后,我发现可以解析一个函数类型(它的返回类型及其参数类型)使用部分模板专业化和 功能重载。
以下是实现std::function
:
template<class T> class Function { };
// Parse the function type
template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> {
union Pointers {
Res (*func)(Obj*, ArgTypes...);
Res (Obj::*mem_func)(ArgTypes...);
};
typedef Res Callback(Pointers&, Obj&, ArgTypes...);
Pointers ptrs;
Callback* callback;
static Res call_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (*ptrs.func)(&obj, args...);
}
static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
return (obj.*(ptrs.mem_func))(args...);
}
public:
Function() : callback(0) { }
// Parse the function type
Function(Res (*func)(Obj*, ArgTypes...)) {
ptrs.func = func;
callback = &call_func;
}
// Parse the function type
Function(Res (Obj::*mem_func)(ArgTypes...)) {
ptrs.mem_func = mem_func;
callback = &call_mem_func;
}
Function(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
}
Function& operator=(const Function& function) {
ptrs = function.ptrs;
callback = function.callback;
return *this;
}
Res operator()(Obj& obj, ArgTypes... args) {
if(callback == 0) throw 0; // throw an exception
return (*callback)(ptrs, obj, args...);
}
};
用法:
#include <iostream>
struct Funny {
void print(int i) {
std::cout << "void (Funny::*)(int): " << i << std::endl;
}
};
void print(Funny* funny, int i) {
std::cout << "void (*)(Funny*, int): " << i << std::endl;
}
int main(int argc, char** argv) {
Funny funny;
Function<void(Funny*, int)> wmw;
wmw = &Funny::print; // void (Funny::*)(int)
wmw(funny, 10); // void (Funny::*)(int)
wmw = &print; // void (*)(Funny*, int)
wmw(funny, 8); // void (*)(Funny*, int)
return 0;
}
答案 1 :(得分:3)
它是如何做的(我相信)未定义(但我这里没有标准的副本)。
但鉴于需要涵盖所有不同的可能性,我觉得破译其工作原理的确切定义将非常困难:所以我不会尝试。
但我想你想知道仿函数是如何工作的,而且它们相对简单。所以这是一个简单的例子。
这些对象就像功能一样 它们在模板代码中非常有用,因为它们通常允许您交替使用对象或函数。关于仿函数的好处是它们可以保持状态(一种穷人的封闭)。
struct X
{
int operator()(int x) { return doStuff(x+1);}
int doStuff(int x) { return x+1;}
};
X x; // You can now use x like a function
int a = x(5);
您可以使用仿函数保持状态来保存参数或对象或指向成员方法(或其任意组合)的指针。
struct Y // Hold a member function pointer
{
int (X::*member)(int x);
int operator(X* obj, int param) { return (obj->*member)(param);}
};
X x;
Y y;
y.member = &X::doStuff;
int a = y(&x,5);
甚至可以进一步绑定参数。所以现在你需要提供的只是其中一个参数。
struct Z
{
int (X::*member)(int x);
int param;
Z(int (X::*m)(int), int p) : member(m), param(p) {}
int operator()(X* obj) { return (obj->*member)(param);}
int operator()(X& obj) { return (obj.*member)(param);}
};
Z z(&X::doStuff,5);
X x;
int a = z(x);
答案 2 :(得分:2)
g ++似乎有一个联合,它可以保留函数指针,成员指针或void指针,它们可能指向一个仿函数。添加重载,适当地标记哪个联合成员有效并且重浇铸到汤中然后它可以工作......
答案 3 :(得分:1)
它们不是函数指针。这就是std :: function的用途。它包装你给它的任何可调用类型。你应该查看boost :: bind-它经常被用来使成员函数指针可以调用为(this,args)。
答案 4 :(得分:1)
回答标题中的问题。 std::function
使用的参数是一个很好的技巧,可以将许多参数作为单个模板参数传递。这些参数是函数的参数类型和返回类型。
碰巧std::function
试图对通用函子进行类型擦除,但这只是巧合。
事实上,很久以前,有一些编译器不接受这种技巧,boost::function
前体具有便携式语法,可以通过该语法传递所有参数分别:
首选语法
boost::function<void(int*, int, int&, float&)> sum_avg;
便携式语法
boost::function4<void, int*, int, int&, float&> sum_avg;
https://www.boost.org/doc/libs/1_68_0/doc/html/function/tutorial.html#id-1.3.16.5.4
所以std::function
的模板参数就是这样工作的,最后,这只是使许多参数看起来像函数调用一样的技巧。此类的函数指针不一定是 。