function C++11 将任意类型的可调用(Callable)对象与函数调用的特征封装到一起。

这里的类是对函数策略的封装,将函数的性质抽象成组件,便于和algorithm库配合使用

基本运算符 和 基本比较符号组件

  1. template<class Arg, class Result>
  2. struct unary_function
  3. {
  4. typedef Arg argument_type;
  5. typedef Result result_type;
  6. };
  7. template<class Arg1, class Arg2, class Result>
  8. struct binary_function
  9. {
  10. typedef Arg1 first_argument_type;
  11. typedef Arg2 second_argument_type;
  12. typedef Result result_type;
  13. };
  14. template<class T>
  15. struct plus : binary_function<T, T, T>
  16. {
  17. T operator()(const T& x, const T& y) const
  18. {
  19. return x + y;
  20. }
  21. };
  22. template<class T>
  23. struct minus :binary_function<T, T, T>
  24. {
  25. T operator()(const T& x, const T& y) const
  26. {
  27. return x - y;
  28. }
  29. };
  30. template<class T>
  31. struct multiplies : binary_function<T, T, T>
  32. {
  33. T operator()(const T& x, const T& y) const
  34. {
  35. return x*y;
  36. }
  37. };
  38. template <class T>
  39. struct modulus : binary_function <T, T, T>
  40. {
  41. T operator() (const T& x, const T& y) const
  42. {
  43. return x%y;
  44. }
  45. };
  46. template<class T>
  47. struct negate :unary_function<T, T>
  48. {
  49. T operator()(const T& x) const
  50. {
  51. return -x;
  52. }
  53. };
  54. template<class T>
  55. struct less :binary_function<T, T, bool>
  56. {
  57. bool operator()(const T&lhs, const T& rhs) const
  58. {
  59. return lhs < rhs;
  60. }
  61. };
  62. template <class T>
  63. struct greater : binary_function<T, T, bool>
  64. {
  65. bool operator()(const T& lhs, const T& rhs) const
  66. {
  67. return lhs > rhs;
  68. }
  69. };
  70. template <class T>
  71. struct equal_to : binary_function <T, T, bool>
  72. {
  73. bool operator() (const T& x, const T& y) const
  74. {
  75. return x == y;
  76. }
  77. };
  78. template<class T>
  79. struct greater_equal : binary_function<T, T, bool>
  80. {
  81. bool operator()(const T& lhs, const T& rhs)
  82. {
  83. return lhs >= rhs;
  84. }
  85. };
  86. template<class T>
  87. struct less_equal : binary_function<T, T, bool>
  88. {
  89. bool operator()(const T& lhs, const T& rhs)
  90. {
  91. return lhs <= rhs;
  92. }
  93. };

逻辑运算组件

对已经封装好的函数组件的运行结果增加一层封装。

  1. template <class Predicate>
  2. class unary_negate
  3. : public unary_function <typename Predicate::argument_type, bool>//参数类型是传入Predicate的参数类型,返回类型为bool
  4. {
  5. protected:
  6. Predicate fn;
  7. public:
  8. explicit unary_negate(const Predicate& pred) : fn(pred) {}
  9. bool operator() (const typename Predicate::argument_type& x) const
  10. {
  11. return !fn(x);
  12. }
  13. };
  14. template <class Predicate>
  15. class binary_negate
  16. : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type, bool>
  17. {
  18. protected:
  19. Predicate fn;
  20. public:
  21. explicit binary_negate(const Predicate& pred) :fn(pred) {}
  22. bool operator() (const typename Predicate::first_argument_type& x,
  23. const typename Predicate::second_argument_type& y) const
  24. {
  25. return !fn(x, y);
  26. }
  27. };

参数绑定

将要调用的参数保存在结构中,调用的时候再传入

使用typename 和 模板 来指明返回类型 和 参数类型

建议使用explicit来避免隐式类型转换

  1. template<class Operation>
  2. class binder1st
  3. : public binary_function<typename Operation::first_argument_type, typename Operation::second_argument_type, typename Operation::result_type>
  4. {
  5. protected:
  6. typename Operation::first_argument_type val;//要绑定的参数
  7. Operation op;
  8. public:
  9. explicit binder1st(const Operation& operation, const typename Operation::first_argument_type x) :op(operation),val(x) {}
  10. typename Operation::result_type operator()(const typename Operation::second_argument_type& xs)
  11. {
  12. return op(val, x);
  13. }
  14. };
  15. //绑定第二个参数
  16. template<class Operation>
  17. class binder2nd
  18. : public binary_function<typename Operation::first_argument_type, typename Operation::second_argument_type, typename Operation::result_type>
  19. {
  20. protected:
  21. typename Operation::second_argument_type val;
  22. Operation op;
  23. public:
  24. explicit binder2nd(const Operation& operation, const typename Operation::second_argument_type x) :op(operation),val(x) {}
  25. typename Operation::result_type operator()(const typename Operation::first_argument_type& xs)
  26. {
  27. return op(x, val);
  28. }
  29. };

不定参数的绑定

底层数据 结构用tuple来实现,对于调用参数的获取,维护一个tuple index 模板类,去在模板中递归生成对应下标,这一部分涉及大量的模板元编程。

  • 为什么要生成所有参数的下标?

    需要知道参数的位置,顺序,这样对应着进行模板展开,从tuple中get出对应位置的参数传入函数进行调用
  • 如何生成?

    模板展开 + 模板偏特化
  1. template <std::size_t...>
  2. struct tuple_indices {};
  3. //生成下标 注意第二个模板是一个类模板 , 第一和第三个模板参数作为展开的边界
  4. template <std::size_t Sp, class IntTuple, std::size_t Ep>
  5. struct make_indices_imp;
  6. template <std::size_t Sp, std::size_t... Indices, std::size_t Ep>
  7. struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep>
  8. {
  9. typedef typename make_indices_imp<Sp + 1, tuple_indices<Indices..., Sp>, Ep>::type type;
  10. };
  11. //对结束位置进行特化
  12. template <std::size_t Ep, std::size_t... Indices>
  13. struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep>
  14. {
  15. typedef tuple_indices<Indices...> type;
  16. };
  17. template <std::size_t Ep, std::size_t Sp = 0>
  18. struct make_tuple_indices
  19. {
  20. typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
  21. };

具体tuple的内部实现改天再写。。。

  1. //绑定不定数目 不定类型的参数
  2. //底层数据通过tuple来保存实现
  3. 要实现
  4. template <class F, class... Args>
  5. struct binder
  6. {
  7. //使用std::forward 进行完美转发
  8. //可见 http://en.cppreference.com/w/cpp/utility/forward
  9. binder(F&& f, Args&&... args) :data(std::forward<F>(f), std::forward<Args>(args)...) {}
  10. inline auto operator()()
  11. {
  12. typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, Args...> >::value, 1>::type index_type;
  13. return run2(index_type());
  14. }
  15. template <std::size_t... Indices>
  16. void run2(tuple_indices<Indices...>)
  17. {
  18. //模板展开
  19. invoke(std::move(std::get<0>(data)), std::move(std::get<Indices>(data))...);
  20. }
  21. inline auto invoke(F&& f, Args&&... args)
  22. {
  23. //f 作为函数指针 ,args 作为参数传入
  24. return std::forward<F>(f)(std::forward<Args>(args)...);
  25. }
  26. //使用tuple来保存数据
  27. std::tuple<F,Args...> data;
  28. };
  29. template <class F, class... Args >
  30. ministl::binder<F,Args...> bind(F&& f, Args&&... args)
  31. {
  32. return binder<F, Args...>(std::forward<F>(f), std::forward<Args>(args)...);
  33. }

对类成员函数进行调用

大部分可以用lambda 代替,不过还是写一下,不作重点,精髓还是在于bind

  1. template <class S, class T> mem_fun_t<S, T> mem_fun(S(T::*f)())
  2. {
  3. return mem_fun_t<S, T>(f);
  4. }
  5. template <class S, class T, class A>
  6. class mem_fun1_t : public binary_function <T*, A, S>
  7. {
  8. S(T::*pmem)(A);
  9. public:
  10. explicit mem_fun1_t(S(T::*p)(A)) : pmem(p) {}
  11. S operator() (T* p, A x) const
  12. {
  13. return (p->*pmem)(x);
  14. }
  15. };
  16. template <class S, class T, class A> mem_fun1_t<S, T, A> mem_fun(S(T::*f)(A))
  17. {
  18. return mem_fun1_t<S, T, A>(f);
  19. }
  20. template <class S, class T>
  21. class const_mem_fun_t : public unary_function <T*, S>
  22. {
  23. S(T::*pmem)() const;
  24. public:
  25. explicit const_mem_fun_t(S(T::*p)() const) : pmem(p) {}
  26. S operator() (T* p) const
  27. {
  28. return (p->*pmem)();
  29. }
  30. };
  31. template <class S, class T> const_mem_fun_t<S, T> mem_fun(S(T::*f)() const)
  32. {
  33. return const_mem_fun_t<S, T>(f);
  34. }
  35. template <class S, class T, class A>
  36. class const_mem_fun1_t : public binary_function <T*, A, S>
  37. {
  38. S(T::*pmem)(A) const;
  39. public:
  40. explicit const_mem_fun1_t(S(T::*p)(A) const) : pmem(p) {}
  41. S operator() (T* p, A x) const
  42. {
  43. return (p->*pmem)(x);
  44. }
  45. };
  46. template <class S, class T, class A> const_mem_fun1_t<S, T, A> mem_fun(S(T::*f)(A) const)
  47. {
  48. return const_mem_fun1_t<S, T, A>(f);
  49. }
  50. template <class S, class T>
  51. class mem_fun_ref_t : public unary_function <T, S>
  52. {
  53. S(T::*pmem)();
  54. public:
  55. explicit mem_fun_ref_t(S(T::*p)()) : pmem(p) {}
  56. S operator() (T& p) const
  57. {
  58. return (p.*pmem)();
  59. }
  60. };
  61. template<class S,class T,class A>
  62. class mem_fun1_ref_t : public binary_function<T, S, A>
  63. {
  64. S(T::*pmem)(A);
  65. public:
  66. explicit mem_fun1_ref_t(S(T::*p)(A)) :pmem(p) {}
  67. S operator()(T& p, A x) const
  68. {
  69. return (p.*pmem)(x);
  70. }
  71. };
  72. template <class S, class T>
  73. class const_mem_fun_ref_t : public unary_function <T, S>
  74. {
  75. S(T::*pmem)() const;
  76. public:
  77. explicit const_mem_fun_ref_t(S(T::*p)() const) : pmem(p) {}
  78. S operator() (T& p) const
  79. {
  80. return (p.*pmem)();
  81. }
  82. };
  83. template <class S, class T, class A>
  84. class const_mem_fun1_ref_t : public binary_function <T, A, S>
  85. {
  86. S(T::*pmem)(A) const;
  87. public:
  88. explicit const_mem_fun1_ref_t(S(T::*p)(A) const) : pmem(p) {}
  89. S operator() (T& p, A x) const
  90. {
  91. return (p.*pmem)(x);
  92. }
  93. };
  94. //Returns a function object that encapsulates member function f of type T.
  95. template <class S, class T>
  96. mem_fun_ref_t<S, T> mem_fun_ref(S(T::*f)())
  97. {
  98. return mem_fun_ref_t<S, T>(f);
  99. }
  100. template <class S, class T, class A>
  101. mem_fun1_ref_t<S, T, A> mem_fun_ref(S(T::*f)(A))
  102. {
  103. return mem_fun1_ref_t<S, T, A>(f);
  104. }
  105. template <class S, class T>
  106. const_mem_fun_ref_t<S, T> mem_fun_ref(S(T::*f)() const)
  107. {
  108. return const_mem_fun_ref_t<S, T>(f);
  109. }
  110. template <class S, class T, class A>
  111. const_mem_fun1_ref_t<S, T, A> mem_fun_ref(S(T::*f)(A) const)
  112. {
  113. return const_mem_fun1_ref_t<S, T, A>(f);
  114. }

从零开始写STL—functional的更多相关文章

  1. 从零开始写STL - 智能指针

    从零开始写STL - 智能指针 智能指针的分类及其特点: scoped_ptr:初始化获得资源控制权,在作用域结束释放资源 shared_ptr: 引用计数来控制共享资源,最后一个资源的引用被释放的时 ...

  2. 从零开始写STL—栈和队列

    从零开始写STL-栈和队列 适配器模式 意图:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 主要解决:主要解决在软件系统中,常常要将 ...

  3. 从零开始写STL—容器—vector

    从0开始写STL-容器-vector vector又称为动态数组,那么动态体现在哪里?vector和一般的数组又有什么区别?vector中各个函数的实现原理是怎样的,我们怎样使用会更高效? 以上内容我 ...

  4. 从零开始写STL—模板元编程之any

    any class any; (since C++17) The class any describes a type-safe container for single values of any ...

  5. 从零开始写STL—哈希表

    static const int _stl_num_primes = 28; template<typename T, typename Hash = xhash<T>> cl ...

  6. 从零开始写STL—模板元编程之tuple

    tuple Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generali ...

  7. 从零开始写STL—set/map

    这一部分只要把搜索树中暴露的接口封装一下,做一些改动. set源码剖析 template<typename T> class set { public: typedef T key_typ ...

  8. 从零开始写STL-内存部分-内存分配器allocator

    从零开始写STL-内存部分-内存分配器allocator 内存分配器是什么? 一般而言,c++的内存分配和释放是这样操作的 >>class Foo{ //...}; >>Foo ...

  9. 从零开始写STL-容器-list

    从零开始写STL-容器-list List 是STL 中的链表容器,今天我们将通过阅读和实现list源码来解决一下问题: List内部的内存结构是如何实现的? 为什么List的插入复杂度为O(1)? ...

随机推荐

  1. JVM补充一

    一.为什么废弃永久代(PermGen) 2.1 官方说明 参照JEP122:http://openjdk.java.net/jeps/122,原文截取: Motivation This is part ...

  2. 登录脚本重构by封装

    package com.gubai.selenium; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; imp ...

  3. COGS 1. 加法问题 (水体日常)

    这是一个经典的入门问题,通过此问题,你可以学会如何使用该评测系统. [问题描述] 现在有两个实数,分别是A和B.请你从文件中读取A和B,计算它们的和A+B,并把它输出到文件中.(保留到整数) [输入格 ...

  4. [Python學習筆記] 使用xlwings 插入註解 (forked 版本)

    到今天為止 xlwings 還沒有插入註解的功能 去原始開發者的 Github Pull Requests 他說之前有人有建議要加入這個功能 但他還沒更新~ 如果需要使用 Python 來插入註解的話 ...

  5. PHP CLI应用的调试原理

    我们在Eclipse里选中一个PHP文件,右键选择Debug As->PHP CLI Application. 所谓CLI应用,是指这种脚本文件不需要任何Web服务器即可运行,当然, PHP运行 ...

  6. 总结vue2.0 配置的实例方法

    总结vue2.0 配置的实例方法 http://www.php.cn/js-tutorial-369603.html

  7. QT_6_QMainWindow

    QMainWindow 1.1. 菜单栏 1.1.1. 只有一个 1.1.2. QMenuBar *bar = MenuBar(); 1.1.3. 设置到窗口中 setMenuBar(bar); 1. ...

  8. [BZOJ2120]:数颜色(分块?)

    题目传送门 我感觉这种题没必要扯淡题目大意了,没啥用. 暴力过掉,擦了个边. 主要是讲一下这道题我用到的卡常. 首先,0,1标记我用的位运算,位运算符跑的要比正常的+,-,×,÷,true,false ...

  9. upupoo(网页壁纸)自主修改一:农历

    最近在使用一款upupoo的壁纸软件,感觉还可以,主要是对其中html可设置为壁纸方面情有独钟 前几天在它的网页区发现了一个壁纸,感觉挺好: 感觉内容有点少,今天在工作空余时间就在其中加上了农历,同时 ...

  10. JS常用字符串处理方法应用总结

    这篇文章主要总结了JS常用字符串的处理方法,需要的朋友可以参考下   1.indexOf()方法,从前往后查找字符串位置,大小写敏感,从0开始计数.同理,lastIndexOf() 方法从后往前,两个 ...