lamboda表达式:
[] // 没有定义任何变量。使用未定义变量会导致错误。
[x, &y] // x 以传值方式传入(默认),y 以引用方式传入。
[&] // 任何被使用到的外部变量皆隐式地以引用方式加以使用。
[=] // 任何被使用到的外部变量皆隐式地以传值方式加以使用。
[&, x] // x 显示地以传值方式加以使用。其余变量以引用方式加以使用。
[=, &z] // z 显示地以引用方式加以使用。其余变量以传值方式加以使用。
// sort algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
//[] // 没有定义任何变量。使用未定义变量会导致错误。
//[x, &y] // x 以传值方式传入(默认),y 以引用方式传入。
//[&] // 任何被使用到的外部变量皆隐式地以引用方式加以使用。
//[=] // 任何被使用到的外部变量皆隐式地以传值方式加以使用。
//[&, x] // x 显示地以传值方式加以使用。其余变量以引用方式加以使用。
//[=, &z] // z 显示地以引用方式加以使用。其余变量以传值方式加以使用。
bool myfunction (int i,int j) { return (i<j); }
struct myclass {
bool operator() (int i,int j) { return (i<j);}
} myobject;
int main () {
int myints[] = {32,71,12,45,26,80,53,33};
std::vector<int> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33
// using default comparison (operator <):
std::sort (myvector.begin(), myvector.begin()+4); //(12 32 45 71)26 80 53 33
std::sort(myvector.begin()+4, myvector.end(), [](int p1, int p2) ->bool{ return p1 < p2;});
/*
// using function as comp
std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)
// using object as comp
std::sort (myvector.begin(), myvector.end(), myobject); //(12 26 32 33 45 53 71 80)
*/
std::for_each(myvector.begin(), myvector.end(), [](int p) ->int {printf("-> %d ", p); return p;});
/*
// print out content:
std::cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
*/
std::cout << '\n';
return 0;
}
右值:
引用: https://www.cnblogs.com/5iedu/p/7698710.html
这篇文章里讲右值讲的很好,它提到了一个最重要的本质: 左值”和“右值”是表达式结果的一种属性;
1. 左值和右值
(1)两者区别:
①左值:能对表达式取地址、或具名对象/变量。一般指表达式结束后依然存在的持久对象。
②右值:不能对表达式取地址,或匿名对象。一般指表达式结束就不再存在的临时对象。
(2)右值的分类
①将亡值(xvalue,eXpiring value):指生命期即将结束的值,一般是跟右值引用相关的表达式,这样表达式通常是将要被移动的对象,如返回类型为T&&的函数返回值(如std::move)、经类型转换为右值引用的对象(如static_cast<T&&>(obj))、xvalue类对象的成员访问表达式也是一个xvalue(如Test().memberdata,注意Test()是个临时对象)
②纯右值(prvalue, PureRvalue):按值返回的临时对象、运算表达式产生的临时变对象、原始字面量和lambda表达式等。
①表达式是由运算符(operator)和运算对象(operand)构成的计算式。字面值和变量是最简单的表达式,函数的返回值也被认为是表达式。
②表达式是可求值的,对表达式求值将得到一个结果,这个结果有两个属性:类型和值类别,而表达式的值类别必属于左值、将亡值或纯右值三者之一。
③“左值”和“右值”是表达式结果的一种属性。通常用“左值”来指代左值表达式,用“右值”指代右值表达式。
#include <iostream>
int main(int argc, char* argv[])
{
//1. 左、右值判断
int i = 0;
//int& ri = i++; // compile errer "error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’"
int&& ri = i++; //i++为右值,表达式返回是i的拷贝,是个匿名变量。故为右值。
int& li = ++i; //++i返回的是i本身,是具名变量,故为左值
return 0;
}
闭包:
其实闭包概念只是为了函数式编程中使用的, 函数式编程中要把函数更加灵活化, 可以作为返回值, 可以作为参数, 可以作为变量的值, 并且最重要的是,闭包实际上是函数式编程在突破变量作用域的语法限制基础上,想要使用面向对象编程的一些优点而做出的靠拢, IBM的这边文章中 https://www.ibm.com/developerworks/cn/linux/l-cn-closure/, 从变量作用域的角度讲了闭包的由来, 实际上可以看出,闭包是函数式编程突破一些限制而变得更强大的一种手段,想使用对象编程的有点,但又保持函数式编程形式的一种靠拢; 一句话本质, 对象是附有行为的数据,而闭包是附有数据的行为。
函数是一阶值(First-class value),即函数可以作为另一个函数的返回值或参数,还可以作为一个变量的值。
函数可以嵌套定义,即在一个函数内部可以定义另一个函数。
而相应的在对象编程中, C++语言也想借鉴函数式编程的一些有点, 所以也支持了闭包,
引用: https://blog.csdn.net/tennysonsky/article/details/77440152
这边文章讲的很好, 点明了C++中的重载()操作符, lamboda表达式, std::bind就是闭包支持的形式;
重载()操作符可以结合"std::function"模板类来查看其接近于函数式编程的功能;
"闭包有很多种定义,一种说法是,闭包是带有上下文的函数。说白了,就是有状态的函数。更直接一些,不就是个类吗?换了个名字而已。
一个函数,带上了一个状态,就变成了闭包了。那什么叫 “带上状态” 呢? 意思是这个闭包有属于自己的变量,这些个变量的值是创建闭包的时候设置的,并在调用闭包的时候,可以访问这些变量。"
std::bind的用例:
// bind example
#include <iostream> // std::cout
#include <functional> // std::bind
// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide (double x, double y) {return x/y;}
struct MyPair {
double a,b;
double multiply() {return a*b;}
};
int main () {
using namespace std::placeholders; // adds visibility of _1, _2, _3,...
// binding functions:
auto fn_five = std::bind (my_divide,10,2); // returns 10/2
std::cout << fn_five() << '\n'; // 5
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x
std::cout << fn_invert(10,2) << '\n'; // 0.2
auto fn_rounding = std::bind<int> (my_divide,_1,_2); // returns int(x/y)
std::cout << fn_rounding(10,3) << '\n'; // 3
MyPair ten_two {10,2};
// binding members:
auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
std::cout << bound_member_fn(ten_two) << '\n'; // 20
auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
std::cout << bound_member_data() << '\n'; // 10
return 0;
}
总结,函数式编程, 对象编程,各有各的有点, 各有各的限制, 而实际当中它们都互相借鉴而已不破坏自己形式的情况下使用了对方的优点, 函数编程有闭包, C++中也有越来越多的和函数式编程功能非常接近的功能模板;
Is the behavior of return x++; defined?
It is defined.
It returns the value of x
before incrementation. If x
is a local(non-static) variable this post incrementation has no effect since local variables of a function cease to exist once the function returns. But if x
is a local static variable, global variable or an instance variable( as in your case), its value will be incremented after return.
看例子:
#include <stdio.h>
int a = 1;
int fun() {
return a++;
}
int main() {
printf("a1: %d, a2:%d\n", fun(), a);
printf("a3: %d\n", a);
return 0;
}
结果:
a1: 1, a2:1
a3: 2
lamboda表达式和函数不同的地方:
lamboda突破性的地方在于,它可以捕获它所嵌入的代码环境中的任何变量来使用,而不仅仅依赖于传参,这是和函数最大的不同。这一点很强大,不通过要注意,表达式执行时,它捕获的外部变量的值,在定义嵌入的位置时就决定了,这一点不同于传参,传入的参数的值是在调用位置决定的。