在C++中,存在“可调用对象”这么一个概念。准确来说,可调用对象有如下几种定义:
1、是一个函数指针
2、是一个具有operator()成员函数的类对象(仿函数)
3、是一个可转换为函数指针的类对象
4、是一个类成员(函数)指针
- #include
- using namespace std;
-
- void func(void)
- {}
-
- struct Foo
- {
- void operator()(void){}
- };
-
- struct Bar
- {
- using fr_t = void(*)(void);
-
- static void func(void)
- {
- printf("%s %s %d\n", __FILE__, __func__, __LINE__);
- }
-
- operator fr_t(void)
- {
- return func;
- }
- };
-
- struct A
- {
- int a_;
-
- void mem_func(void)
- {
- printf("%s %s %d\n", __FILE__, __func__, __LINE__);
- }
- };
-
- int main()
- {
- void (*func_ptr)(void) = &func; ///1、函数指针
- func_ptr();
-
- Foo foo;
- foo(); ///2、仿函数
-
- Bar bar;
- bar(); ///3、可被转化为函数指针的类对象
-
- void (A::*mem_func_ptr)(void) = &A::mem_func; ///4、类成员函数指针
-
- int A::*mem_obj_ptr = &A::a_; ///类成员指针
-
- A aa;
- (aa.*mem_func_ptr)();
- aa.*mem_obj_ptr = 123;
-
- return 0;
- }
从上述可以看到,除了类成员指针之外,上面定义涉及的对象均为可以像一个函数那样做调用操作。
在C++11中,像上面例子中的这些对象(func_ptr,foo,bar,mem_func_ptr,mem_obj_ptr)都被称为可调用对象。相对应的,这些对象的类型被统称为“可调用类型”。
现在,C++11通过std::function和std::bind统一了可调用对象的各自操作。
std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。
- #include
- #include
- using namespace std;
-
- void func(void)
- {
- cout << __FUNCTION__ << endl;
- }
-
- class Foo
- {
- public:
- static int foo_func(int a)
- {
- cout << __FUNCTION__ << "(" << a << ") ->: ";
- return a;
- }
- };
-
- class Bar
- {
- public:
- int operator()(int a)
- {
- cout << __FUNCTION__ << "(" << a << ") ->: ";
- return a;
- }
-
- };
-
- int main()
- {
- function<void(void)> fr1 = func; ///绑定一个普通函数
- fr1();
-
- ///绑定一个类的静态成员函数
- std::function<int(int)> fr2 = Foo::foo_func;
- cout << fr2(123) << endl;
-
- Bar bar;
- fr2 = bar;
- cout << fr2(123) << endl;
-
- return 0;
- }
运行结果如下:

从上面我们可以看到std::function的使用方法,当我们给std::function填入合适的函数签名(即一个函数类型,只需要包括返回值和参数表)之后,它就变成了一个可以容纳所有这一类调用方式的“函数包装器”。
- #include
- #include
- using namespace std;
-
- class A
- {
- public:
- A(const std::function<void()> & f):callback_(f){}
-
- void notify(void)
- {
- callback_();
- }
-
- private:
- std::function<void()> callback_;
- };
-
- class Foo
- {
- public:
- void operator()(void)
- {
- cout << __FUNCTION__ << endl;
- }
- };
-
- int main()
- {
- Foo foo;
- A aa(foo);
-
- aa.notify();
-
- return 0;
- }
从上面的例子中可以看到,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数。
std::function作为函数入参示例
- #include
- #include
- using namespace std;
-
- void call_when_even(int x, const std::function<void(int)>& f)
- {
- if (!(x & 1))
- {
- f(x);
- }
- }
-
- void output(int x)
- {
- cout << x << " ";
- }
-
- int main()
- {
- for(int i = 0; i < 10; i++)
- {
- call_when_even(i, output);
- }
- cout << endl;
-
- return 0;
- }
从上面的例子中可以看到,std::function比普通函数指针更灵活和便利。
std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。
通俗来讲,它主要有两大作用:
1、将可调用对象与其参数一起绑定成一个仿函数。
2、将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。
- #include
- #include
- using namespace std;
-
- void call_when_even(int x, const std::function<void(int)>& f)
- {
- if (!(x & 1))
- {
- f(x);
- }
- }
-
- void output(int x)
- {
- cout << x << " ";
- }
-
- void output_add_2(int x)
- {
- cout << x + 2 << " ";
- }
-
-
- int main()
- {
- {
- auto fr = std::bind(output, std::placeholders::_1);
- for(int i = 0; i < 10; i++)
- {
- call_when_even(i, fr);
- }
- cout << endl;
- }
-
- {
- auto fr = std::bind(output_add_2, std::placeholders::_1);
- for(int i = 0; i < 10; i++)
- {
- call_when_even(i, fr);
- }
- cout << endl;
- }
-
- return 0;
- }
我们使用std::bind在函数外部通过绑定不同的函数,控制了最后的执行结果。
我们使用auto fr保存std::bind的返回结果,因为我们不关心std::bind真正的返回类型(实际上std::bind的返回类型是一个stl内部定义的仿函数类型),只需要知道它是一个仿函数,可以直接赋值给一个std::function。当然,这里直接使用std::function类型来保存std::bind的返回值也是可以的。
std::placeholders::_1是一个占位符,代表这个位置将在函数调用时,被传入的第一个参数所替代。
- #include
- #include
- using namespace std;
-
- void output(int x, int y)
- {
- cout << x << " " << y << endl;
- }
-
- int main()
- {
- ///输出1,2
- std::bind(output, 1, 2)();
-
- ///输出2,2
- std::bind(output, std::placeholders::_1, 2)(2);
-
- ///输出3,444
- std::bind(output, 3, std::placeholders::_1)(444);
-
- ///error,调用时没有第二个参数
- ///std::bind(output, 3, std::placeholders::_2)(333);
-
- ///调用时第一个参数被吞掉了
- ///输入1, 333
- std::bind(output, 1, std::placeholders::_2)(7, 333);
-
- ///输入7, 333
- std::bind(output, std::placeholders::_1, std::placeholders::_2)(7, 333);
-
- return 0;
- }
上面对std::bind的返回结果直接施以调用。可以看到,std::bind可以直接绑定函数的所有参数,也可以绑定部分参数。
在绑定部分参数的时候,通过std::placeholders,来决定空位参数将会属于调用发生时的第几个参数。
- #include
- #include
- using namespace std;
-
- class A
- {
- public:
- int i_ = 0;
-
- void output(int x, int y)
- {
- cout << x << " " << y << endl;
- }
- };
-
- int main()
- {
- A a;
-
- std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1, std::placeholders::_2);
-
- fr(1, 2);
-
- std::function<int& (void)> fr_i = std::bind(&A::i_, &a);
-
- fr_i() = 123;
-
- cout << a.i_ << endl;
-
- return 0;
- }
fr的类型是std::function
之后,std::bind将A的成员i_的指针和a绑定,返回的结果被放入std::function