目录
- void lamada_value_capture(){
- int value=1;
- auto copy_value=[value]{
- return value;
- }
- value=100;
- auto stored_value = copy_value();
- std::cout << "stored_value = " << stored_value << std::endl;
-
- // 这时, stored_value == 1, 而 value == 100.
- // 因为 copy_value 在创建时就保存了一份 value 的拷贝
- }
与引用传参类似,引用捕获保存的是引用,值会发生变化
- oid lamada_value_capture(){
- int value=1;
- auto copy_value=[&value]{
- return value;
- }
- value=100;
- auto stored_value = copy_value();
- std::cout << "stored_value = " << stored_value << std::endl;
- // 这时, stored_value == 100, value == 100.
- // 因为 copy_value 保存的是引用
-
- }
• [] 空捕获列表• [name1, name2, . . . ] 捕获一系列变量• [&] 引用捕获 , 让编译器自行推导捕获列表• [=] 值捕获 , 让编译器执行推导引用列表
- #include
- #include
- int main()
- {
- auto importance=std::make_unique<int>(1);
- auto add=[[v1 = 1, v2 = std::move(important)](int x,int y)->int{
- return x+y+v1+(*v2);
-
- }
- std::cout << add(3,4) << std::endl;
- }
1.2.泛型Lambda
- auto add=[](auto x,auto y)
- {
- return x+y
- }
- add(1,2);
- add(1.2,3.2);
- #include
-
- using foo=void(int);
-
- void function(foo f)//定义在参数列表中的函数类型 foo 被视为退化后的函数指针类型 foo*
- {
- foo(1);// 通过函数指针调用函数
- }
- int main()
- {
- auto f=[](int value)
- {
- std::cout << value << std::endl;
- }
- function(f);// 传递闭包对象,隐式转换为 foo* 类型的函数指针值
- f(1);// lambda 表达式调用
- }
- #include
- #include
-
- int foo(int para)
- {
- return para;
- }
- int main()
- {
- //std::function包装了一个返回值为 int, 参数为 int 的函数
- std::function<int(int)> fun=foo;
- int importance=10;
- std::function<int(int)> func2=[&](int value)->int
- {
- return 1+value+importance;
- }
- std::cout << func(10) << std::endl;
- std::cout << func2(10) << std::endl;
-
- }
- #include
- #include
- using namespace std;
-
- int TestFunc(int a, char c, float f)
- {
- cout << a << endl;
- cout << c << endl;
- cout << f << endl;
-
- return a;
- }
-
- int main()
- {
- auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
- bindFunc1(10); //等于TestFunc(10,'A', 100.1)
-
- cout << "=================================\n";
-
- auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
- bindFunc2('B', 10); //等于TestFunc(10,'B', 100.1)
-
- cout << "=================================\n";
-
- auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
- bindFunc3(100.1, 30, 'C'); //等于TestFunc(30,'C', 100.1)
-
- return 0;
- }
- class Foo {
- const char*&& right = "this is a rvalue"; // 此处字符串字面量为右值
- public:
- void bar() {
- right = "still rvalue"; // 此处字符串字面量为右值
- }
- };
- int main() {
- const char* const &left = "this is an lvalue"; // 此处字符串字面量为左值
- }
- std::vector<int> foo() {
- std::vector<int> temp = {1, 2, 3, 4};
- return temp;
- }
- std::vector<int> v = foo();
- #include
- #include
- void reference(std::string& str) {
- std::cout << " 左值" << std::endl;
- }
- void reference(std::string&& str) {
- std::cout << " 右值" << std::endl;
- }
- int main()
- {
- std::string lv1 = "string,"; // lv1 是一个左值
- // std::string&& r1 = lv1; // 非法, 右值引用不能引用左值
- std::string&& rv1 = std::move(lv1); // 合法, std::move 可以将左值转移为右值
- std::cout << rv1 << std::endl; // string,
- const std::string& lv2 = lv1 + lv1; // 合法, 常量左值引用能够延长临时变量的生命周期
- // lv2 += "Test"; // 非法, 常量引用无法被修改
- std::cout << lv2 << std::endl; // string,string
- std::string&& rv2 = lv1 + lv2; // 合法, 右值引用延长临时对象生命周期
- rv2 += "Test"; // 合法, 非常量引用能够修改临时变量
- std::cout << rv2 << std::endl; // string,string,string,Test
- reference(rv2); // 输出左值
- return 0; }
- #include
- class A
- {
- public:
- int* pointer;
- A():pointer(new int(1))
- {
- std::cout<<" 构造"<
- }
- A(A&a):pointer(new int(*a.pointer))
- {
- std::cout << " 拷贝" << pointer << std::endl;
- }
- A(A&& a):pointer(a.pointer) {
- a.pointer = nullptr;
- std::cout << " 移动" << pointer << std::endl;
- }
- ~A()
- {
- std::cout << " 析构" << pointer << std::endl;
- delete pointer;
- }
- };
- A return_rvalue(bool test)
- {
- A a,b;
- if(test )return a;
- else return b;
- //static_cast(b);
-
- }
- int main()
- {
- A obj = return_rvalue(false);
- std::cout << "obj:" << std::endl;
- std::cout << obj.pointer << std::endl;
- std::cout << *obj.pointer << std::endl;
- return 0;
- }
代码结果:
构造0x603010//a
构造0x603030//b
移动0x603030//b
析构0//b
析构0x603010//a
obj:
0x603030//b
1
析构0x603030
分析:
1.
首先会在
return_rvalue
内部构造两个
A
对象,于是获得两个构造函数的输出;
2.
函数返回后,产生一个将亡值,被
A
的移动构造(
A(A&&)
)引用,从而延长生命周期,并将这个右值中的指针拿到,保存到了 obj
中,而
将亡值的指针被设置为 nullptr
,防止了这块内存区域被销毁
3.5完美转发
前面我们提到了,一个声明的右值引用其实是一个左值。这就为我们进行参数转发(传递)造成了
问题:
- #include
- void reference(int& v) {
- std::cout << " 左值" << std::endl;
- }
- void reference(int&& v) {
- std::cout << " 右值" << std::endl;
- }
- template <typename T>
- void pass(T&& v) {
- std::cout << " 普通传参:";
- reference(v); // 始终调用 reference(int&)
- }
- int main() {
- std::cout << " 传递右值:" << std::endl;
- pass(1); // 1 是右值, 但输出是左值
- std::cout << " 传递左值:" << std::endl;
- int l = 1;
- pass(l); // l 是左值, 输出左值
- return 0; }
传递右值:
普通传参: 左值
传递左值:
普通传参: 左值
分析:对于
pass(1)
来说,虽然传递的是右值,但由于
v
是一个引用,所以同时也是左值。因此
reference(v)
会调用
reference(int&)
,输出『左值』。而对于
pass(l)
而言,
l
是一个左值,为什么
会成功传递给
pass(T&&)
呢?
这是基于
引用坍缩规则
的:在传统
C++
中,我们不能够对一个引用类型继续进行引用,但
C++
由
于右值引用的出现而放宽了这一做法,从而产生了引用坍缩规则,允许我们对引用进行引用,既能左引 用,又能右引用。但是却遵循如下规则:
函数形式参数 实参 推导 T&
左引用
T&
T&
右引用
T&
T&&
左引用
T&
T&&
右引用
T& &
总结 两者都右才是右
完美转发就是基于上述规律产生的。所谓完美转发,就是为了让我们在传递参数的时候,保持原来
的参数类型(左引用保持左引用,右引用保持右引用)。为了解决这个问题,我们应该使用
std::forward 来进行参数的转发(传递):
- #include
-
- void reference(int& v) {
- std::cout << " 左值" << std::endl;
- }
- void reference(int&& v) {
- std::cout << " 右值" << std::endl;
- }
- template <typename T>
- void pass(T&& v) {
- std::cout << " 普通传参:";
- reference(v); // 始终调用 reference(int&)
- std::cout << " std::move 传参: ";
- reference(std::move(v));
- std::cout << " std::forward 传参: ";
- reference(std::forward
(v)); - std::cout << "static_cast
传参: " ; - reference(static_cast
(v)); - }
- int main() {
- std::cout << " 传递右值:" << std::endl;
- pass(1); // 1 是右值, 但输出是左值(临时变量)
- std::cout << " 传递左值:" << std::endl;
- int l = 1;
- pass(l); // l 是左值, 输出左值
- return 0; }
结果:
传递右值:
普通传参: 左值
std::move 传参: 右值
std::forward 传参: 右值
static_cast 传参: 右值
传递左值:
普通传参: 左值
std::move 传参: 右值
std::forward 传参: 左值
static_cast 传参: 左值