从零开始写STL—functional
function C++11 将任意类型的可调用(Callable)对象与函数调用的特征封装到一起。
这里的类是对函数策略的封装,将函数的性质抽象成组件,便于和algorithm库配合使用
基本运算符 和 基本比较符号组件
template<class Arg, class Result>
struct unary_function
{
typedef Arg argument_type;
typedef Result result_type;
};
template<class Arg1, class Arg2, class Result>
struct binary_function
{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
template<class T>
struct plus : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const
{
return x + y;
}
};
template<class T>
struct minus :binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const
{
return x - y;
}
};
template<class T>
struct multiplies : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const
{
return x*y;
}
};
template <class T>
struct modulus : binary_function <T, T, T>
{
T operator() (const T& x, const T& y) const
{
return x%y;
}
};
template<class T>
struct negate :unary_function<T, T>
{
T operator()(const T& x) const
{
return -x;
}
};
template<class T>
struct less :binary_function<T, T, bool>
{
bool operator()(const T&lhs, const T& rhs) const
{
return lhs < rhs;
}
};
template <class T>
struct greater : binary_function<T, T, bool>
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs > rhs;
}
};
template <class T>
struct equal_to : binary_function <T, T, bool>
{
bool operator() (const T& x, const T& y) const
{
return x == y;
}
};
template<class T>
struct greater_equal : binary_function<T, T, bool>
{
bool operator()(const T& lhs, const T& rhs)
{
return lhs >= rhs;
}
};
template<class T>
struct less_equal : binary_function<T, T, bool>
{
bool operator()(const T& lhs, const T& rhs)
{
return lhs <= rhs;
}
};
逻辑运算组件
对已经封装好的函数组件的运行结果增加一层封装。
template <class Predicate>
class unary_negate
: public unary_function <typename Predicate::argument_type, bool>//参数类型是传入Predicate的参数类型,返回类型为bool
{
protected:
Predicate fn;
public:
explicit unary_negate(const Predicate& pred) : fn(pred) {}
bool operator() (const typename Predicate::argument_type& x) const
{
return !fn(x);
}
};
template <class Predicate>
class binary_negate
: public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type, bool>
{
protected:
Predicate fn;
public:
explicit binary_negate(const Predicate& pred) :fn(pred) {}
bool operator() (const typename Predicate::first_argument_type& x,
const typename Predicate::second_argument_type& y) const
{
return !fn(x, y);
}
};
参数绑定
将要调用的参数保存在结构中,调用的时候再传入
使用typename 和 模板 来指明返回类型 和 参数类型
建议使用explicit来避免隐式类型转换
template<class Operation>
class binder1st
: public binary_function<typename Operation::first_argument_type, typename Operation::second_argument_type, typename Operation::result_type>
{
protected:
typename Operation::first_argument_type val;//要绑定的参数
Operation op;
public:
explicit binder1st(const Operation& operation, const typename Operation::first_argument_type x) :op(operation),val(x) {}
typename Operation::result_type operator()(const typename Operation::second_argument_type& xs)
{
return op(val, x);
}
};
//绑定第二个参数
template<class Operation>
class binder2nd
: public binary_function<typename Operation::first_argument_type, typename Operation::second_argument_type, typename Operation::result_type>
{
protected:
typename Operation::second_argument_type val;
Operation op;
public:
explicit binder2nd(const Operation& operation, const typename Operation::second_argument_type x) :op(operation),val(x) {}
typename Operation::result_type operator()(const typename Operation::first_argument_type& xs)
{
return op(x, val);
}
};
不定参数的绑定
底层数据 结构用tuple来实现,对于调用参数的获取,维护一个tuple index 模板类,去在模板中递归生成对应下标,这一部分涉及大量的模板元编程。
- 为什么要生成所有参数的下标?
需要知道参数的位置,顺序,这样对应着进行模板展开,从tuple中get出对应位置的参数传入函数进行调用- 如何生成?
模板展开 + 模板偏特化
template <std::size_t...>
struct tuple_indices {};
//生成下标 注意第二个模板是一个类模板 , 第一和第三个模板参数作为展开的边界
template <std::size_t Sp, class IntTuple, std::size_t Ep>
struct make_indices_imp;
template <std::size_t Sp, std::size_t... Indices, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep>
{
typedef typename make_indices_imp<Sp + 1, tuple_indices<Indices..., Sp>, Ep>::type type;
};
//对结束位置进行特化
template <std::size_t Ep, std::size_t... Indices>
struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep>
{
typedef tuple_indices<Indices...> type;
};
template <std::size_t Ep, std::size_t Sp = 0>
struct make_tuple_indices
{
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
};
具体tuple的内部实现改天再写。。。
//绑定不定数目 不定类型的参数
//底层数据通过tuple来保存实现
要实现
template <class F, class... Args>
struct binder
{
//使用std::forward 进行完美转发
//可见 http://en.cppreference.com/w/cpp/utility/forward
binder(F&& f, Args&&... args) :data(std::forward<F>(f), std::forward<Args>(args)...) {}
inline auto operator()()
{
typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, Args...> >::value, 1>::type index_type;
return run2(index_type());
}
template <std::size_t... Indices>
void run2(tuple_indices<Indices...>)
{
//模板展开
invoke(std::move(std::get<0>(data)), std::move(std::get<Indices>(data))...);
}
inline auto invoke(F&& f, Args&&... args)
{
//f 作为函数指针 ,args 作为参数传入
return std::forward<F>(f)(std::forward<Args>(args)...);
}
//使用tuple来保存数据
std::tuple<F,Args...> data;
};
template <class F, class... Args >
ministl::binder<F,Args...> bind(F&& f, Args&&... args)
{
return binder<F, Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}
对类成员函数进行调用
大部分可以用lambda 代替,不过还是写一下,不作重点,精髓还是在于bind
template <class S, class T> mem_fun_t<S, T> mem_fun(S(T::*f)())
{
return mem_fun_t<S, T>(f);
}
template <class S, class T, class A>
class mem_fun1_t : public binary_function <T*, A, S>
{
S(T::*pmem)(A);
public:
explicit mem_fun1_t(S(T::*p)(A)) : pmem(p) {}
S operator() (T* p, A x) const
{
return (p->*pmem)(x);
}
};
template <class S, class T, class A> mem_fun1_t<S, T, A> mem_fun(S(T::*f)(A))
{
return mem_fun1_t<S, T, A>(f);
}
template <class S, class T>
class const_mem_fun_t : public unary_function <T*, S>
{
S(T::*pmem)() const;
public:
explicit const_mem_fun_t(S(T::*p)() const) : pmem(p) {}
S operator() (T* p) const
{
return (p->*pmem)();
}
};
template <class S, class T> const_mem_fun_t<S, T> mem_fun(S(T::*f)() const)
{
return const_mem_fun_t<S, T>(f);
}
template <class S, class T, class A>
class const_mem_fun1_t : public binary_function <T*, A, S>
{
S(T::*pmem)(A) const;
public:
explicit const_mem_fun1_t(S(T::*p)(A) const) : pmem(p) {}
S operator() (T* p, A x) const
{
return (p->*pmem)(x);
}
};
template <class S, class T, class A> const_mem_fun1_t<S, T, A> mem_fun(S(T::*f)(A) const)
{
return const_mem_fun1_t<S, T, A>(f);
}
template <class S, class T>
class mem_fun_ref_t : public unary_function <T, S>
{
S(T::*pmem)();
public:
explicit mem_fun_ref_t(S(T::*p)()) : pmem(p) {}
S operator() (T& p) const
{
return (p.*pmem)();
}
};
template<class S,class T,class A>
class mem_fun1_ref_t : public binary_function<T, S, A>
{
S(T::*pmem)(A);
public:
explicit mem_fun1_ref_t(S(T::*p)(A)) :pmem(p) {}
S operator()(T& p, A x) const
{
return (p.*pmem)(x);
}
};
template <class S, class T>
class const_mem_fun_ref_t : public unary_function <T, S>
{
S(T::*pmem)() const;
public:
explicit const_mem_fun_ref_t(S(T::*p)() const) : pmem(p) {}
S operator() (T& p) const
{
return (p.*pmem)();
}
};
template <class S, class T, class A>
class const_mem_fun1_ref_t : public binary_function <T, A, S>
{
S(T::*pmem)(A) const;
public:
explicit const_mem_fun1_ref_t(S(T::*p)(A) const) : pmem(p) {}
S operator() (T& p, A x) const
{
return (p.*pmem)(x);
}
};
//Returns a function object that encapsulates member function f of type T.
template <class S, class T>
mem_fun_ref_t<S, T> mem_fun_ref(S(T::*f)())
{
return mem_fun_ref_t<S, T>(f);
}
template <class S, class T, class A>
mem_fun1_ref_t<S, T, A> mem_fun_ref(S(T::*f)(A))
{
return mem_fun1_ref_t<S, T, A>(f);
}
template <class S, class T>
const_mem_fun_ref_t<S, T> mem_fun_ref(S(T::*f)() const)
{
return const_mem_fun_ref_t<S, T>(f);
}
template <class S, class T, class A>
const_mem_fun1_ref_t<S, T, A> mem_fun_ref(S(T::*f)(A) const)
{
return const_mem_fun1_ref_t<S, T, A>(f);
}
从零开始写STL—functional的更多相关文章
- 从零开始写STL - 智能指针
从零开始写STL - 智能指针 智能指针的分类及其特点: scoped_ptr:初始化获得资源控制权,在作用域结束释放资源 shared_ptr: 引用计数来控制共享资源,最后一个资源的引用被释放的时 ...
- 从零开始写STL—栈和队列
从零开始写STL-栈和队列 适配器模式 意图:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 主要解决:主要解决在软件系统中,常常要将 ...
- 从零开始写STL—容器—vector
从0开始写STL-容器-vector vector又称为动态数组,那么动态体现在哪里?vector和一般的数组又有什么区别?vector中各个函数的实现原理是怎样的,我们怎样使用会更高效? 以上内容我 ...
- 从零开始写STL—模板元编程之any
any class any; (since C++17) The class any describes a type-safe container for single values of any ...
- 从零开始写STL—哈希表
static const int _stl_num_primes = 28; template<typename T, typename Hash = xhash<T>> cl ...
- 从零开始写STL—模板元编程之tuple
tuple Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generali ...
- 从零开始写STL—set/map
这一部分只要把搜索树中暴露的接口封装一下,做一些改动. set源码剖析 template<typename T> class set { public: typedef T key_typ ...
- 从零开始写STL-内存部分-内存分配器allocator
从零开始写STL-内存部分-内存分配器allocator 内存分配器是什么? 一般而言,c++的内存分配和释放是这样操作的 >>class Foo{ //...}; >>Foo ...
- 从零开始写STL-容器-list
从零开始写STL-容器-list List 是STL 中的链表容器,今天我们将通过阅读和实现list源码来解决一下问题: List内部的内存结构是如何实现的? 为什么List的插入复杂度为O(1)? ...
随机推荐
- MyBatis学习(四)
前言 最近比较松懈,下班回家后也懒得学习了.今晚实在是看不下去了,争取时间学习.社会上有这么多的资源,就看谁能抢的多吧.今天就说说MyBatis的动态SQL吧 正文 动态 SQL 通常要做的事情是有条 ...
- sybase sql anywhere 5.0 安装后sybase central中无法打开视图等的解决办法
无法打开的原因初步分析要用英文版的xp,后来在如下处发现问题,是sql anywhere的版本太旧了, 可能没有使用Unicode编码,设置一下如下选项可以解决问题.
- Android(java)学习笔记169:服务(service)之为什么使用服务
1.服务 service 长期在后台运行的进程,一般没有应用程序界面 2.进程线程和应用程序之间的关系 应用程序开启,系统启动一个Linux进程,所有的组件都是运行在同一个进程的同一个线程(mai ...
- 什么是python 中的顶层代码?
在python语言中我们经常会听到顶层代码的说法,但是什么是顶层代码? 在python中,我们是以缩进来区分代码层次的,所以顶层代码指的是缩进为0个空格的代码. 看如下例子: PP = 3.14 de ...
- java-基于泛型和反射机制的通用比较器实现
一.前言 Java的比较器是用来对List集合进行排序用的,分为内部比较器和外部比较器两类 内部比较器:被排序的类要 implements Comparable 类,并实现compareTo方法. 外 ...
- 响应式布局(CSS3弹性盒flex布局模型)
传统的布局方式都是基于盒模型的 利用display.position.float来布局有一定局限性 比如说实现自适应垂直居中 随着响应式布局的流行,CSS3引入了更加灵活的弹性布局模型 flex弹性布 ...
- index 定义 v-for 未使用变量 实际是没有 :key="index"
需要有 :key="index" <Checkbox :label="item.key" :key="index" v-for=&qu ...
- SQL Server数据库的除法默认向下取整,要返回小数的解决方法
num1; / 1000.0 num2; * 1.0 num3; num4; 结果:
- QT_3
1.QT中命名的规范和常用的快捷键 1.1 命名规范: 类名:首字母大写 多个单词时单词与单词之间首 字母大写 函数名:变量名称 首字母小写 多个单词时,单词和单词之间首字母大写 1. ...
- Java中的类加载器--Class loader
学习一下Java中的类加载器,这个是比较底层的东西,好好学习.理解一下. 一.类加载器的介绍 1.类加载器:就是加载类的工具,在java程序中用到一个类,java虚拟机首先要把这个类的字节码加载到内 ...