C++11,lambda,包装器

1.lambda(可以说是该匿名函数的统称)

1.捕捉分两种:值捕捉和引用捕捉

复制代码
int main()
{
    int a =10,b = 20;
            //a是值拷贝,b是引用拷贝
 auto add = [a,&b](int x,int y)->int{return x + y + a + b;}
    return 0;
}

值捕捉在函数体内是不允许被修改的,引用捕捉允许被修改且会影响外部的该变量的值。

全局域与局部静态变量可以直接使用且不允许被捕捉,同一个变量也不允许被捕捉两次及以上。

lambda也是可以直接载全局中实现的,只是一般写在函数内。

3.隐式值捕捉:[=]=>默认将该函数内的局部变量的值都捕捉进来

隐式引用捕捉:[&]=>默认将该函数内的局部变量的引用都捕捉进来

上面两种即使全捕捉,但函数体未使用的变量实际上并没有被捕捉。

混合捕捉:

复制代码
//除了a,b是值捕捉,其他都引用捕捉
[&,a,b]

4.lambda是不能递归:

lambda是匿名函数给函数变量初始化完了之后才能使用(常规函数没有运行初始化这种概念才可以递归)因此lambda的内部无法调用未初始化完的函数变量。

复制代码
//类似于我初始化我自己,逻辑矛盾
int a = a + 10;

5.mutable

允许值捕捉的变量的值也能被修改,但这里修改的值并不会影响外部局部变量的值

复制代码
auto add[a,&b](int x,int y) mutable
{
    a++;
    return x + y;
}

6.lambda的原理(就是仿函数)

cpp 复制代码
class Rate
{
public:
	Rate(double rate)
		: _rate(rate)
	{
	}
	double operator()(double money, int year)
	{
		return money * _rate * year;
	}
private:
	double _rate;
};

int main()
{
	double rate = 0.49;

	// lambda
	auto r2 = [rate](double money, int year) {
		return money * rate * year;
	};

	// 函数对象
	Rate r1(rate);
	r1(10000, 2);
	r2(10000, 2);


	return 0;
}

反汇编

cpp 复制代码
//二者的形成逻辑很像
auto r2 = [rate](double money, int year) {
		return money * rate * year;
	};
00007FF6D1DB20EB  lea         rdx,[rate]  
00007FF6D1DB20EF  lea         rcx,[r2]  
00007FF6D1DB20F3  call        `main'::`2'::<lambda_1>::<lambda_1> (07FF6D1DB18D0h)  
00007FF6D1DB20F8  nop  

	// 函数对象
	Rate r1(rate);
00007FF6D1DB20F9  movsd       xmm1,mmword ptr [rate]  
00007FF6D1DB20FE  lea         rcx,[r1]  
00007FF6D1DB2102  call        Rate::Rate (07FF6D1DB1474h)  
00007FF6D1DB2107  nop  
cpp 复制代码
	//二者插入值得方式完全一样
    r1(10000, 2);
00007FF6D1DB2108  mov         r8d,2  
00007FF6D1DB210E  movsd       xmm1,mmword ptr [__real@40c3880000000000 (07FF6D1DBABB0h)]  
00007FF6D1DB2116  lea         rcx,[r1]  
00007FF6D1DB211A  call        Rate::operator() (07FF6D1DB1479h)  
00007FF6D1DB211F  nop  
	r2(10000, 2);
00007FF6D1DB2120  mov         r8d,2  
00007FF6D1DB2126  movsd       xmm1,mmword ptr [__real@40c3880000000000 (07FF6D1DBABB0h)]  
00007FF6D1DB212E  lea         rcx,[r2]  
00007FF6D1DB2132  call        `main'::`2'::<lambda_1>::operator() (07FF6D1DB1DC0h)  
00007FF6D1DB2137  nop  

2.默认移动构造和默认移动赋值

在没有自主实现得移动构造,析构函数,拷贝构造,拷贝赋值中的任意一个时编译器才会生成一个默认移动构造/移动赋值。

两个得功能也完全一样:内置类型成员值拷贝,自定义类型成员变量优先调用移动构造,没有在调用拷贝构造。

3.deflaut

其实所有得默认成员函数都可以通过deflaut来强制生成.

cpp 复制代码
//强制生成默认构造
List_node() = deflaut;
//强制生成拷贝构造
List_node(cosnt List_node& a) = deflaut;

delete:不允许外部调用该成员函数,例ostream的拷贝函数就不允许调用

STLC++11的最核心变化就是unorded_map的unoreded_set容器的出现,与容器中push系列/insert/emplace系列这里面与右值引用相关的接口。

4.包装器

1.function(函数模板同时还是一个参数包),原理无需懂,在functional头文件中。

cpp 复制代码
template<class T>
class function

template<class Ret,class... Args>
class function<Ret<Args...>>

使用:(function的参数个数,类型,返回值都要与右侧的可调用对象的相同)

cpp 复制代码
#include<functional>

int f(int a, int b)
{
	return a + b;
}

struct Functor
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};



int main()
{
	// 包装各种可调用对象,常规函数,仿函数,匿名函数
	function<int(int, int)> f1 = f;
	function<int(int, int)> f2 = Functor();
	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
return 0;
}

说白了就是代替c语言的函数指针的。

cpp 复制代码
class Plus
{
public:
	Plus(int n = 10)
		:_n(n)
	{}

	static int plusi(int a, int b)
	{
		return a + b;
	}

	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}

private:
	int _n;
};int main()
{
	//都要取地址
	function<int(int, int)> f4 = &Plus::plusi;
	cout << f4(1, 1) << endl;
    //常规成员函数还有this指针的隐藏函数,这里要写一个Plus类型的函数
	function<double(Plus*, double, double)> f5 = &Plus::plusd;
	Plus pl;
	cout << f5(&pl, 1.111, 1.1) << endl;
    function<double(Plus, double, double)> f5 = &Plus::plusd;
	Plus pl;
	cout << f5(pl, 1.111, 1.1) << endl;
	return 0;
}

&是必然的,static成员函数没有this指针,因此不用传Plus,但常规成员函数有this指针,因此要传。

此处的Plus变量其实不能说完全就是this指针,其的本质是.*,有

cpp 复制代码
pl.*(成员函数地址);

bind(返回一个functional类型)

起的本质是一个函数模板,也就是一个可调用对象的包装器,用于调整参数个数与参数顺序。

placeholders,是占位符的集合

cpp 复制代码
//常要using来简化placeholders
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int Sub(int a, int b)
{
	return (a - b) * 10;
}

int SubX(int a, int b, int c)
{
	return (a - b - c) * 10;
}

int main()
{
//第一次bind可以视为初始化placeholders
	auto sub1 = bind(Sub, _1, _2);
	cout << sub1(10, 5) << endl;
        //就可以反过来传参了
	auto sub2 = bind(Sub, _2, _1);
	cout << sub2(10, 5) << endl;

	// 调整参数个数
    //锁死了两个参数,只有_1能传了
	auto sub3 = bind(Sub, 100, _1);
	cout << sub3(5) << endl;

	auto sub4 = bind(Sub, _1, 100);
	cout << sub4(5) << endl;

	// 分别绑死第123个参数
	auto sub5 = bind(SubX, 100, _1, _2);
	cout << sub5(5, 1) << endl;
	auto sub6 = bind(SubX, _1, 100, _2);
	cout << sub6(5, 1) << endl;
	auto sub7 = bind(SubX, _1, _2, 100);
	cout << sub7(5, 1) << endl;

    function<double(Plus&&, double, double)> f6 = &Plus::plusd;
    Plus pd;
    cout << f6(move(pd), 1.1, 1.1) << endl;
    cout << f6(Plus(), 1.1, 1.1) << endl;

	// 成员函数对象进行绑死,就不需要每次都传递了
    // 还能帮助function传plusd的地址
	function<double(double, double)> f6 = bind(&Plus::plusd, Plus(), _1, _2);
	cout << f6(1.1, 1.1) << endl;




	return 0;
}

-1,-2的意思是代表要传的第几个实参,而非这个实参在所有参数中的排列顺序。

相关推荐
sycmancia2 小时前
Qt——布局管理区(二)
开发语言·前端·qt
云栖梦泽2 小时前
Linux内核与驱动:11.设备树
linux·c++
傻啦嘿哟2 小时前
Python 操作 Word 页眉页脚完整指南
开发语言·c#
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(五):<线程同步与互斥>线程互斥
linux·运维·服务器·c语言·c++·学习·ubuntu
阿kun要赚马内2 小时前
Python装饰器的原理详解
开发语言·python
kyle~2 小时前
FANUC机械臂---R寄存器
开发语言·c++·机器人·fanuc
山甫aa2 小时前
哈希表的变化(链表数组强化)----从零开始的数据结构
数据结构·哈希算法·散列表
长沙红胖子Qt2 小时前
Qt实用技巧:多QLabel不规则间距像素对齐文本方式实现
开发语言·qt·字符间距·动态控制
码云数智-园园2 小时前
Go并发编程避坑指南:如何彻底消灭数据竞争(Data Race)
开发语言