当前位置:   article > 正文

C++11:std::function 函数封装器

函数封装器

std::function

c++11 新特性,包含在 #include <functional> 头文件中.

定义

  • 类模板 std::function 是一种通用的、多态的函数封装器;

可以封装任何可以调用的目标实体,如普通函数、Lambda 表达式、函数指针以及函数对象等,封装器可存储、复制和调用等,且封装器类型仅仅依赖于调用特征,不依赖于可调用元素自身的类型。

  • std::function 对象是对可调用实体的一种类型安全包装(像函数指针这类可调用实体,是类型不安全的);

  • std::function 对象包装其它任意的函数对象,被包装的函数对象具有类型为 T1, ..., TN 的 N 个参数,并且返回一个可转换到 R 类型的值。

  • std::function 使用模板转换构造函数接收被包装的函数对象。

实现原理

  1. 通过类的多态,即通过虚表来达到多态;

  2. 通过 C 语言的函数指针来实现;

单参数类模板,是 function<int(int)> 等格式的类模板:

  1. template<class R, typename Arg0>
  2. class myfunction<R(Arg0)>
  3. {
  4. public:
  5. R operator()(Arg0 arg0)
  6. {
  7. return ...;
  8. }
  9. }

若实现可以调用不同的函数,模板函数首先要有一个指针,而且该指针具有多态性(C++ 通过基继承和虚表),故需要有一个基类指针使得所有继承于该类的子类成员,使用 virtual 关键字创建虚表:

  1. template<class R, typename Arg0>
  2. class myfunction<R(Arg0)> function
  3. {
  4. private:
  5. class __callbase
  6. {
  7. public:
  8. virtual R operator()(Arg0 arg0) = 0;
  9. virtual ~__callbase(){ }
  10. };
  11. __callbase *base_;
  12. public:
  13. R operator()(Arg0 arg0)
  14. {
  15. return (*__callbase)(arg0);
  16. }
  17. };

实现子类:

  1. class myfunction<R(Arg0)> function
  2. {
  3. private:
  4. template<typename F>
  5. class __callable : public __callbase {
  6. public:
  7. // 增加指向赋值给 function 类的函数指针或函数类对象
  8. callable(F functor) : functor(functor){ }
  9. // 指向后重载操作符进行直接调用
  10. virtual R operatr()(Arg0 arg0){
  11. return functor(arg0);
  12. }
  13. private:
  14. // 指向具体的函数或函数类对象,由模板推导
  15. F functor;
  16. };
  17. public:
  18. template<typename F>
  19. myfunction(F f):base_(new __callable<F>(f)){
  20. }
  21. ~myfunction(){
  22. if(base_){
  23. delete base_;
  24. base_ = nullptr;
  25. }
  26. }
  27. };

应用

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. #include <functional>
  5. std::function<int(int)> callback; // 函数封装器对象实例
  6. int (*fun_ptr)(int); // 函数指针
  7. int fun1(int a) // 普通函数
  8. {
  9. std::cout << "Hello, function!" << endl;
  10. return a;
  11. }
  12. template <typename T> // 模板函数
  13. T fun2(T a)
  14. {
  15. return a + 2;
  16. }
  17. struct add // 仿函数对象
  18. {
  19. int operator()(int a)
  20. {
  21. return a + 3;
  22. }
  23. };
  24. auto fun3 = [&](int a) -> int { // lambda 表达式
  25. return a + 4;
  26. };
  27. template <typename T> // 模板对象仿函数
  28. struct sub
  29. {
  30. T operator()(T a)
  31. {
  32. return a + 5;
  33. }
  34. };
  35. template <typename T> // 模板对象静态函数
  36. struct foo2
  37. {
  38. static T foo(T a)
  39. {
  40. return a * 4;
  41. }
  42. };
  43. struct foo3
  44. { // 对象静态函数
  45. static int foo(int a)
  46. {
  47. return a * 3;
  48. }
  49. };
  50. class TestClass
  51. {
  52. public:
  53. int ClassMember(int a, int b)
  54. {
  55. std::cout << "Hello, function!" << endl;
  56. return a + b;
  57. } // 类成员函数
  58. static int StaticMember(int a) { return a; } // 类静态函数
  59. };
  60. int main(int, char **)
  61. {
  62. //! 1. 封装器对象调用包装的实体
  63. fun_ptr = fun1;
  64. callback = fun_ptr;
  65. cout << callback(10) << endl;
  66. //! 2. 包装普通函数
  67. callback = fun1;
  68. cout << callback(20) << endl;
  69. //! 3. 包装模板函数
  70. callback = fun2<int>;
  71. cout << callback(30) << endl;
  72. //! 4. 包装仿函数对象
  73. callback = add();
  74. cout << callback(40) << endl;
  75. //! 5. 包装 lambda 表达式
  76. callback = fun3;
  77. cout << callback(50) << endl;
  78. //! 6. 包装模板对象仿函数
  79. callback = sub<int>();
  80. cout << callback(60) << endl;
  81. //! 7. 包装模板对象静态函数
  82. callback = foo2<int>::foo;
  83. cout << callback(70) << endl;
  84. //! 8. 包装对象静态函数
  85. callback = foo3::foo;
  86. cout << callback(80) << endl;
  87. //! 9. 包装对象静态函数
  88. callback = foo3::foo;
  89. cout << callback(90) << endl;
  90. //! 10. 类成员函数
  91. TestClass testObj;
  92. // 占位符,绑定可调用实体的第一个参数
  93. callback22 = std::bind(&TestClass::ClassMember, testObj
  94. , std::placeholders::_1, std::placeholders::_2);
  95. cout << callback22(100, 1) << endl;
  96. //! 11. 类静态函数
  97. callback = TestClass::StaticMember;
  98. cout << callback(110) << endl;
  99. //! 12. std::function 拷贝、移动赋值运算
  100. std::function<int(int)> callback2 = callback; // 拷贝赋值运算符
  101. std::cout << callback2(120) << std::endl;
  102. std::function<int(int)>&& callback3 = std::move(callback); // 移动赋值运算符
  103. std::cout << callback2(130) << std::endl;
  104. }

注意事项

  • 类成员函数都有一个默认的参数 this,由此,类成员函数不能直接赋值给 std::function,通过 std::bind 转换函数签名,绑定函数第一个形参;

  • 类函数不进行绑定,则需要通过对类进行类静态函数描述后,利用第二个参数 function 类型将类中以 void* 指针调用类函数(而非 this->fun),如果有需要还需要将指针类型进行强制转换为类类型(增加强制转换、类静态函数、引入类地址);

  • 关于可调用实体转换为 std::function 对象需要遵守以下两条原则:

    • 转换后的 std::function 对象的参数能转换为可调用实体的参数;

    • 可调用实体的返回值能转换为 std::function 对象的返回值。

  • std::function 对象最大的用处就是在实现函数回调,使用者需要注意,它不能被用来检查相等或者不相等,但是可以与 NULL 或者 nullptr 进行比较。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/555645
推荐阅读
相关标签
  

闽ICP备14008679号