赞
踩
c++11 新特性,包含在 #include <functional>
头文件中.
可以封装任何可以调用的目标实体,如普通函数、Lambda 表达式、函数指针以及函数对象等,封装器可存储、复制和调用等,且封装器类型仅仅依赖于调用特征,不依赖于可调用元素自身的类型。
std::function 对象是对可调用实体的一种类型安全包装(像函数指针这类可调用实体,是类型不安全的);
std::function 对象包装其它任意的函数对象,被包装的函数对象具有类型为 T1, ..., TN 的 N 个参数,并且返回一个可转换到 R 类型的值。
std::function 使用模板转换构造函数接收被包装的函数对象。
通过类的多态,即通过虚表来达到多态;
通过 C 语言的函数指针来实现;
单参数类模板,是 function<int(int)> 等格式的类模板:
- template<class R, typename Arg0>
- class myfunction<R(Arg0)>
- {
- public:
- R operator()(Arg0 arg0)
- {
- return ...;
- }
- }
若实现可以调用不同的函数,模板函数首先要有一个指针,而且该指针具有多态性(C++ 通过基继承和虚表),故需要有一个基类指针使得所有继承于该类的子类成员,使用 virtual
关键字创建虚表:
- template<class R, typename Arg0>
- class myfunction<R(Arg0)> function
- {
- private:
- class __callbase
- {
- public:
- virtual R operator()(Arg0 arg0) = 0;
- virtual ~__callbase(){ }
- };
-
- __callbase *base_;
-
- public:
- R operator()(Arg0 arg0)
- {
- return (*__callbase)(arg0);
- }
- };

实现子类:
- class myfunction<R(Arg0)> function
- {
- private:
- template<typename F>
- class __callable : public __callbase {
- public:
- // 增加指向赋值给 function 类的函数指针或函数类对象
- callable(F functor) : functor(functor){ }
-
- // 指向后重载操作符进行直接调用
- virtual R operatr()(Arg0 arg0){
- return functor(arg0);
- }
- private:
- // 指向具体的函数或函数类对象,由模板推导
- F functor;
- };
- public:
- template<typename F>
- myfunction(F f):base_(new __callable<F>(f)){
- }
-
- ~myfunction(){
- if(base_){
- delete base_;
- base_ = nullptr;
- }
- }
- };

- #include <iostream>
- #include <string>
- using namespace std;
-
- #include <functional>
-
- std::function<int(int)> callback; // 函数封装器对象实例
-
- int (*fun_ptr)(int); // 函数指针
-
- int fun1(int a) // 普通函数
- {
- std::cout << "Hello, function!" << endl;
- return a;
- }
-
- template <typename T> // 模板函数
- T fun2(T a)
- {
- return a + 2;
- }
-
- struct add // 仿函数对象
- {
- int operator()(int a)
- {
- return a + 3;
- }
- };
-
- auto fun3 = [&](int a) -> int { // lambda 表达式
- return a + 4;
- };
-
- template <typename T> // 模板对象仿函数
- struct sub
- {
- T operator()(T a)
- {
- return a + 5;
- }
- };
-
- template <typename T> // 模板对象静态函数
- struct foo2
- {
- static T foo(T a)
- {
- return a * 4;
- }
- };
-
- struct foo3
- { // 对象静态函数
- static int foo(int a)
- {
- return a * 3;
- }
- };
-
- class TestClass
- {
- public:
- int ClassMember(int a, int b)
- {
- std::cout << "Hello, function!" << endl;
- return a + b;
- } // 类成员函数
- static int StaticMember(int a) { return a; } // 类静态函数
- };
-
- int main(int, char **)
- {
- //! 1. 封装器对象调用包装的实体
- fun_ptr = fun1;
- callback = fun_ptr;
- cout << callback(10) << endl;
-
- //! 2. 包装普通函数
- callback = fun1;
- cout << callback(20) << endl;
-
- //! 3. 包装模板函数
- callback = fun2<int>;
- cout << callback(30) << endl;
-
- //! 4. 包装仿函数对象
- callback = add();
- cout << callback(40) << endl;
-
- //! 5. 包装 lambda 表达式
- callback = fun3;
- cout << callback(50) << endl;
-
- //! 6. 包装模板对象仿函数
- callback = sub<int>();
- cout << callback(60) << endl;
-
- //! 7. 包装模板对象静态函数
- callback = foo2<int>::foo;
- cout << callback(70) << endl;
-
- //! 8. 包装对象静态函数
- callback = foo3::foo;
- cout << callback(80) << endl;
-
- //! 9. 包装对象静态函数
- callback = foo3::foo;
- cout << callback(90) << endl;
-
- //! 10. 类成员函数
- TestClass testObj;
- // 占位符,绑定可调用实体的第一个参数
- callback22 = std::bind(&TestClass::ClassMember, testObj
- , std::placeholders::_1, std::placeholders::_2);
- cout << callback22(100, 1) << endl;
-
- //! 11. 类静态函数
- callback = TestClass::StaticMember;
- cout << callback(110) << endl;
-
- //! 12. std::function 拷贝、移动赋值运算
- std::function<int(int)> callback2 = callback; // 拷贝赋值运算符
- std::cout << callback2(120) << std::endl;
-
- std::function<int(int)>&& callback3 = std::move(callback); // 移动赋值运算符
- std::cout << callback2(130) << std::endl;
- }

类成员函数都有一个默认的参数 this,由此,类成员函数不能直接赋值给 std::function,通过 std::bind 转换函数签名,绑定函数第一个形参;
类函数不进行绑定,则需要通过对类进行类静态函数描述后,利用第二个参数 function 类型将类中以 void* 指针调用类函数(而非 this->fun),如果有需要还需要将指针类型进行强制转换为类类型(增加强制转换、类静态函数、引入类地址);
关于可调用实体转换为 std::function 对象需要遵守以下两条原则:
转换后的 std::function 对象的参数能转换为可调用实体的参数;
可调用实体的返回值能转换为 std::function 对象的返回值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。