std :: function的模板参数是如何工作的? (实现)

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的内部如何处理成员函数指针非成员函数之间的这种不兼容性指针 。 我不知道这个标准是如何实现像std :: function这样的东西的!

4 Solutions collect form web for “std :: function的模板参数是如何工作的? (实现)”

感谢所有的答案。

我从标准的14.8.2.5-21部分find了一个很好的例子:

 template<class> struct X { }; template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { }; template<class ... Types> struct Y { }; template<class T, class ... Types> struct Y<T, Types& ...> { }; template<class ... Types> int f(void (*)(Types ...)); void g(int, float); // uses primary template X<int> x1; // uses partial specialization; ArgTypes contains float, double X<int(int, float, double)> x2; // uses primary template X<int(float, int)> x3; // use primary template; Types is empty Y<> y1; // uses partial specialization; T is int&, Types contains float, double Y<int&, float&, double&> y2; // uses primary template; Types contains int, float, double Y<int, float, double> y3; // OK; Types contains int, float int fv = f(g); 

它说,使用模板专业化,我们可以parsing函数types (真棒)的模板参数! 以下是关于std :: function如何工作的脏/简单示例:

 template<class T> struct Function { }; template<class T, class Obj, class... Args> struct Function<T(Obj*, Args...)> // Parsing the function type { enum FuncType { FuncTypeFunc, FuncTypeMemFunc }; union FuncPtr { T(*func)(Obj*, Args...); T(Obj::*mem_func)(Args...); }; FuncType m_flag; FuncPtr m_func_ptr; Function(T(*func)(Obj*, Args...)) // void(*)(Funny*, int, int) { m_flag = FuncTypeFunc; m_func_ptr.func = func; } Function(T(Obj::*mem_func)(Args...)) // void(Funny::*)(int, int) { m_flag = FuncTypeMemFunc; m_func_ptr.mem_func = mem_func; } void play(Obj* obj, Args... args) { switch(m_flag) { case FuncTypeFunc: (*m_func_ptr.func)(obj, args...); break; case FuncTypeMemFunc: (obj->*m_func_ptr.mem_func)(args...); break; } } }; 

用法:

 #include <iostream> struct Funny { void done(int i, int j) { std::cout << "Member Function: " << i << ", " << j << std::endl; } }; void done(Funny* funny, int i, int j) { std::cout << "Function: " << i << ", " << j << std::endl; } int main(int argc, char** argv) { Funny funny; Function<void(Funny*, int, int)> f = &Funny::done; // void(Funny::*)(int, int) Function<void(Funny*, int, int)> g = &done; // void(*)(Funny*, int, int) f.play(&funny, 5, 10); // void(Funny::*)(int, int) g.play(&funny, 5, 10); // void(*)(Funny*, int, int) return 0; } 

编辑:感谢Tomek关于union的好的提示,上面的例子改变了将成员/非成员函数指针保存在一个(而不是两个)variables中。


编辑: 马丁·约克是正确的, switch语句不是一个好主意在上面的例子,所以我改变了这个例子完全更好地工作:

 template<class T> class Function { }; template<class Res, class Obj, class... ArgTypes> class Function<Res (Obj*, ArgTypes...)> // Parsing the function type { union Pointers // An union to hold different kind of pointers { Res (*func)(Obj*, ArgTypes...); // void (*)(Funny*, int) Res (Obj::*mem_func)(ArgTypes...); // void (Funny::*)(int) }; 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...); // void (*)(Funny*, int) } static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args) { return (obj.*(ptrs.mem_func))(args...); // void (Funny::*)(int) } public: Function() : callback(0) { } Function(Res (*func)(Obj*, ArgTypes...)) // void (*)(Funny*, int) { ptrs.func = func; callback = &call_func; } Function(Res (Obj::*mem_func)(ArgTypes...)) // void (Funny::*)(int) { 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; } 

它怎么做(我相信)是不确定的(但我没有在这里标准的副本)。

但是,考虑到所有不同的可能性需要被覆盖,我有这样的感觉,破译它是如何工作的确切定义将是非常困难的:所以我不会去尝试。

但是我想你想知道函子是如何工作的,而且相对简单。 所以这里是一个简单的例子。

函子:

这些是像function一样的对象。
它们在模板代码中非常有用,因为它们经常允许您交换使用对象或函数。 关于函数的好处在于它们可以保持状态(一种穷人的closures)。

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

g ++似乎有一个联合可能保留函数指针,成员指针或void指针可能指向一个仿函数。 添加适当的标志哪个工会成员有效的重载,重铸到汤,然后它的工作…

他们不是函数指针。 这就是std :: function所存在的。 它包装你给它的任何可调用的types。 你应该检查boost :: bind-它经常用于使成员函数指针可调用为(this,args)。

  • unique_ptr和shared_ptr之间的区别
  • C ++ 11&C ++ 14中“bsearch”的规范是否有缺陷?
  • 如何使用Boost来实现C ++ 14风格的自动返回types?
  • 析构函数在从构造函数中抛出后调用
  • 我在哪里可以findC ++ 11标准论文?
  • 期货与承诺
  • 现代C ++的实验性特征对于长期项目是否可靠?
  • 为什么我需要std :: condition_variable?
  • C ++ std :: tuple的销毁顺序
  • 如何使我的自定义types使用“基于范围的循环”?
  • 我可以通常/总是使用std :: forward而不是std :: move吗?