小王职场记STL(3)lambda表达式的本质
2019-01-31 本文已影响41人
小王同学加油
上篇文章回顾:
STL理解(1)容器
STL理解(2) 算法
经过上面你了解 ,你应该知道了
-
stl使用大量inline函数,inline函数定义光明正大放到头文件保证不会出错
------想象普通函数定义为什么不可以,想一想 stl的普通函数为什么可以? -
因为放到头文件 模板+重载 构成预编译的多态
本节 介绍的是另一一个点,stl 为什么提供强大的适配能力 。
提供了函数对象,也就是lambda表达式的本质
看一行代码
std::vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//计算容器中小于等于3的元素个数
cout << count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 3));
int count = std::count_if(vec.begin(), vec.end(), [](int x) {return x > 3;})
看不懂没 关系 继续分析
-
函数适配器(很重要)
第一个问题:理解typedef含义
- struct unary_function
定义一个类,然后 里面有几个个成员,没有看出里面的有什么作用呀?
提前定义好成员变量,这样才能实现类型多态的调用
binary_function is a base class for creating function objects with two arguments.
// 一元函数的参数类型和返回值类型
template <class _Arg, class _Result>
//stl_function.h::38
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;
};
std::unary_function<int,bool>
### 应用于仿函数,function adapter
> 对返回值进行逻辑否定:not1, not2
> 对参数进行绑定:bind1st, bind2nd
> 用于函数合成:compose1, compose2
> 用于函数指针:ptr_fun
> 用于成员函数指针:mem_fun, mem_fun_ref
成员类型 | 定义 | 注释 |
---|---|---|
argument_type | 第一个模板参数 (Arg) | ()重载函数的参数类型 |
result_type | 第二个模板参数(Result) | ()重载函数的返回值类型 |
成员类型 | 定义 | 注释 |
---|---|---|
first_argument_type | 第一个模板参数(Arg1) | ()重载函数的第一个参数类型 |
second_argument_type | 第一个模板参数 (Arg2) | ()重载函数的第二个参数类型 |
return_type | 第一个模板参数(Result) | ()重载函数的返回值类型 |
- class binder2nd
//第一次分析:class binder2nd 声明一个类 这个语法你肯定明白
//第二次分析:class binder2nd:public unary_function
//binder2nd继承来了模板类unary_function,typename _Operation::first_argument_type 是参数类型
//vector<int> int就是类型 vector就是模板类 这个对比应该明白
//第三次分析: _<typename _Operation::first_argument_type
//请问 class _Operation是任意类, typename first_argument_type任意类型之间关系是什么?
//但是在stl语法中 typename T 代码是 成员变量的类型(int ,char*) class T 代表类的类型
//vector:base, a.m_i
//T::T
//第四次分析:
// _Operation::second_argument_type 你怎么确定 类_Operation里面一定有成员变量 second_argument_type
//
//binary_function is a base class for creating function objects with two arguments.
//stl 规定 函数对象必须这个类, 这样函数对象之间(虽然不是继承,但是可以调用),但是相互使用了(佩服呀,因此函数对象适配器,可以适配任何同类对象)
// 这就是编译期间的多态
////第五次分析:重载 返回值 operator()(参数)
//typename _Operation::result_type operator()(const typename _Operation::first_argument_type& __x) const
//返回的结果是不是具体类型 是模板 result_type是unary_function实现的
//op(__x, value)
////第6次分析:
//binder2nd::unary_function
//_Operation::binary_function
//这是一次更强大的适配
//这个是第六次分析 关键点
//value 是 binder2nd是创建时候调用构造时候设置的,
//_x 调用函数关系()设置的
//A a(10) 构造(a)
// a(20) 函数调用(a,b)
/**
此函数适配器必须要继承自unary_function对象,满足可配接性。
解释一下可配接性。less_equal类继承自binary_function,便有了内部嵌套类型second_argument_type,
而这个类型正好需要用在binder2nd中,以保存(绑定)某个参数。这样,less_equal就变为了可配接的。
纵观整个适配器系统,基本上都是把某个对象或指向对象的指针封装在一个适配器类中,对适配器的操作最终都会传递到对所包含对象的操作
**/
template <class _Operation>
class binder2nd
: public unary_function<typename _Operation::first_argument_type,
typename _Operation::result_type> {
protected:
_Operation op;//第一个成员变量是:是函数对象
typename _Operation::second_argument_type value;//第二个成员变量是:函数对象的参数
public:
//构造函数 函数对象的创建
binder2nd(const _Operation& __x, // 仿函数
const typename _Operation::second_argument_type& __y)
: op(__x), value(__y) // 绑定的第二个数
{
}
typename _Operation::result_type //返回的结果是不是具体类型 是模板 result_type是unary_function实现的
typename _Operation::result_type operator()(const typename _Operation::first_argument_type& __x) const
{
return op(__x, value);
//这个是第六次分析 关键点
//value 是 binder2nd是创建时候调用构造时候设置的,
//_x 调用函数关系()设置的
//A a(10) 构造(a)
// a(20) 函数调用(a,b)
}
};
- 测试程序;
std::vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//计算容器中小于等于3的元素个数
cout << count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 3));
int count = std::count_if(vec.begin(), vec.end(), [](int x) {return x > 3;})
1548330412420.png
lambda表达式的本质(函数对象)
lambda表达式就是一个函数对象。
当编写了一个lambda表达式的时候,编译器将该表达式翻译成一个未命名类的未命名对象
int num = 100;
auto f = [num](){return num; };//等价于F
class F
{
public:
F(int n) :num(n){}
int operator()() const { return num; }
private:
int num;
};