从零开始写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)? ...
随机推荐
- cnbeta新闻资讯第三方客户端应用
该源码案例是一个cnbeta第三方客户端应用案例,作者ywwxhz,源码cnBeta-reader,cnbeta 的 Android 客户端项目. 源码下载: http://code.662p.com ...
- javascript.json snippets vscode 注释
vscode vue js里面的注释 javascript.json { // Place your global snippets here. Each snippet is defined und ...
- 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度
import java.util.Scanner; /** * [程序38] * * 题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. * * @author Jame ...
- 数据库课程设计 PHP web实现
纪念一下自己写的东西.. 都说很垃圾就是了 直接用XAMPP做的 菜鸟网上学的PHP和HTML <!DOCTYPE html> <html> <head> < ...
- 【2019-5-26】python:字典、常用字符串处理方法及文件操作
一.数据类型:字典 1.字典: 1.1定义字典:dict={'key':'value'} 1.2字典与列表相比,字典取值快,可直接找到key 1.3字典是无序的,不能根据顺序取值 1.4多个元素用逗号 ...
- image的resizeMode属性
Image组件必须在样式中声明图片的宽和高.如果没有声明,则图片将不会被呈现在界面上. 我们一般将Image定义的宽和高乘以当前运行环境的像素密度称为Image的实际宽高. 当Image的实际宽 ...
- sql语句执行顺序与性能优化(1)
一.首先我们看一下mysql的sql语句的书写顺序 . select--distinct--from--on--where--group by--having--聚合函数cube.rollup--or ...
- Django中的Cookie、Session、Token
Cookie : 指望着为了辨别用户身份.进行会话跟踪而存储在用户本地的数据(通常经过加密),是由服务端生成,发送给客户端浏览器,浏览器会将Cookie以key/value保存,下一请求同一网站是就发 ...
- Python:字体颜色
/033[31;1m /033[0m 字体背景颜色 40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色 字体颜色 30:黑 31:红 32:绿 33:黄 ...
- 条款33:避免遮掩继承而来的名称(Avoiding hiding inherited names)
NOTE: 1.derived classes 内的名称会遮掩base classes内的名称.在public继承下从来没有人希望如此. 2.为了让被遮掩的名称再见天日,可使用using 声明方式或转 ...