C++11绑定器bind及function机制( 五 )

std::function具体实现细节,后续再继续说明,函数指针可用于回调功能,函数对象也可用于回调功能,lambda表达式也可用于回调功能,甚至bind绑定适配后的成员函数也可用于回调功能,那么在不确定的情况下 , 通过function机制这样的泛型机制统一表示,就会很方便 。
普通函数:
void hello() {cout << "hello world!" << endl;}void hello_str(string str) {cout << str << endl;}int main() {function<void()> func1 = &hello;// function<void()> func1(&hello); // 两种调用方法均可func1(); //调用func1.operator()() ==> void hello()function<void(string)> func2 = &hello_str;func2("hello world"); //调用func2.operator()(string) ==> void hello_str(string)return 0;}模板函数:
template<typename T>T sum(T a, T b) { return a + b; }int main() {function<int(int, int)> func1 = sum<int>;//调用func1.operator()(int, int) ==> int sum(int, int);cout << func1(3, 5) << endl; //输出8return 0;}lambda表达式:
int main() {function<int(int, int)> func1 = [](int a, int b)->int { return a + b; };cout << func1(3, 5) << endl; //打印8 调用func1.operator()(int, int) ==> 调用lambda表达式返回求和结果return 0;}函数对象:
class PrintAdd1 {public:void operator()(int left, int right) {cout << "sum : " << left + right << endl;}};int main() {function<void(int, int)> func1 = PrintAdd1(); //调用默认无参构造函数创建匿名类对象给func1func1(3, 5); //func1.operator()(int, int) ==> 调用void PrintAdd1.operator(int, int)return 0;}模板函数对象:
template<typename T>class PrintAdd2 {public:void operator()(T left, T right) {cout << "sum : " << left + right << endl;}};int main() {function<void(int, int)> func1 = PrintAdd2<int>(); //调用默认无参构造函数创建匿名模板类对象给func1func1(3, 5); //func1.operator()(int, int) ==> 调用void PrintAdd2.operator()(int, int)return 0;}类静态成员函数:
class StaticClass1 {public:static void hello_static(string s) {cout << s << endl;}};int main() {function<void(string)> func1 = &StaticClass1::hello_static;func1("hello world"); //func1.operator()(string) ==> 调用void hello_static(string)return 0;}模板类静态成员函数:
template<typename T>class StaticClass2 {public:static void hello_static(T out) {cout << out << endl;}};int main() {function<void(string)> func1 = &StaticClass2<string>::hello_static;func1("static.. hello world"); //func1.operator()(string) ==> 调用void StaticClass2<string>::hello_static(string)return 0;}普通类成员函数:
class Test {public:void hello(string str) {cout << str << endl;}};int main() {// function<void(Test *, string)> func = &Test::hello;// func(&Test(), "call Test::hello"); //这种第一个参数传递匿名对象的方法在GCC8.4下不可行 在vs2017下可行 不建议使用匿名对象Test test; //定义对象function<void(Test *, string)> func1 = &Test::hello;func1(&test, "call Test::hello"); //func1.operator(Test *, string) ==> 调用void Test::hello(string)return 0;}模板类成员函数:
template<typename T>class Test2 {public:void hello(T str) {cout << str << endl;}};int main() {Test2<string> test2;function<void(Test2<string> *, string)> func1 = &Test2<string>::hello;func1(&test2, "call template Test::hello"); //func1.operator(Test2 *, string) ==> 调用void Test2<string>::hello(string)return 0;}function底层原理剖析对function用法有基本了解后,为了剖析function底层原理 , 我们还需知道模板的「特例化」以及「可变参数模板』 , 这里不再说明,可参考我以下两篇博文,已经对模板特化和可变参数模板进行了解释:

  • [ 模板全特化与偏特化的概念 ]
  • [ 泛化之美 —— C++11 可变参数模板的妙用 ]
function是C++11特有的一种比函数指针更灵活的机制,现在如果我们要接收一个hello函数,形如:
void hello(string str) { cout << str << endl; }该如何实现呢?function利用了函数对象的手段 , 结合函数指针去调用小括号运算符重载实现,因此理所应当的实现是这样的,内部有一个函数指针_pfunc,并且该函数指针在operator()小括号运算符重载重被调用:
//前向声明模板类template<typename T>class myfunction {};//单个类型参数模板完全特例化template<typename R, typename A1>class myfunction<R(A1)> {public:using PFUNC = R (*)(A1);public:myfunction(PFUNC pfunc) : _pfunc(pfunc) {}R operator()(A1 arg) {return _pfunc(arg);}private:PFUNC _pfunc;};

推荐阅读