auto
- 可以从初始化表达式中推断出变量的类型,大大简化编程工作
- 属于编译器特性,不影响最终的机器码质量,不影响运行效率
#include <iostream>
#include <typeinfo>
using namespace std;
class Person {
};
int main() {
// auto 可以根据变量值自动推断变量类型,且不影响运行效率
auto i = 10; // int
cout << typeid(i).name() << endl;
auto j = 10.0; // double
cout << typeid(j).name() << endl;
auto str = "c++"; // const char *
cout << typeid(str).name() << endl;
auto p = new Person(); // Person *
cout << typeid(p).name() << endl;
return 0;
}
int
double
char const *
class Person *
decltype
- 可以获取变量的类型
int a = 10;
decltype(a) b = 20; // int
Person *p = new Person();
decltype(p) p2; // Person*
nullptr
- 解决了 NULL 的二义性问题
所谓二义性,见如下代码。
#include<iostream>
using namespace std;
void func(int v) {
cout << "func(int)" << endl;
}
void func(int *p) {
cout << "func(int *)" << endl;
}
int main() {
// C++98中会报错,当时 NULL 既代表空指针又代表 0,具有二义性
func(NULL); // func(int)
// C++11出现了 nullptr, 并且 NULL==0, 解决了二义性
func(nullptr); // func(int *)
}
func(int)
func(int *)
按住 ctrl + 鼠标左键 点击 NULL,查看 C++ 源码可以发现:
C++ 中的 NULL 实际上是个宏定义,并且被定义为 0。
常见的空指针写法 int *p = NULL;
源于C++98。
C++11 以后建议使用 nullptr 表示空指针,int *p = nullptr
更好。
快速遍历与数组初始化
#include<iostream>
using namespace std;
int main() {
// int array[] = { 11, 22, 33, 44, 55 }; 与下面完全一样
int array[]{11, 22, 33, 44, 55}; // 更加简洁的初始方式,语法糖
for (int item : array) { // 快速遍历
cout << item << endl;
}
return 0;
}
11
22
33
44
55
Lambda 表达式
- Lambda 表达式的本质就是函数
完整结构(还是结合代码更好理解)
[capture list] (params list) mutable exception-> return type {function body}
- capture list:捕获外部变量列表
- params list:形参列表,不能使用默认参数,不能省略参数名
- mutable:用来说用是否可以修改捕获的变量
- exception:异常设定
- return type:返回值类型
- function body:函数体
有时可以省略部分结构,形式更简洁
- [capture list] (params list) -> return type {function body}
- [capture list] (params list) {function body}
- [capture list] {function body}
首先来一个形式最简单的 Lambda 表达式,注意,Lambda 表达式很多结构可以省略,C++中 []中括号是 Lambda 的标志,绝对不可省略。
#include<iostream>
using namespace std;
int main() {
// 这是形式最简单的 lambda 表达式
// [capture list] {function body}
[] {
cout << "Hello World" << endl;
};
// 运行后没有任何结果
return 0;
}
实际上这么写并没有运行结果,因为根本没有调用函数。调用这个最简单的 Lambda 表达式方法如下:
int main() {
// 调用形式最简单的 lambda 表达式,"()()"
([] {
cout << "Hello World" << endl;
})();
// 输出 Hello World
return 0;
}
Hello World
没错,实际上就是写成了函数的形式 “()()”,很好记。
Lambda 表达式既然是个“表达式”,自然可以被赋值,示例如下:
#include<iostream>
using namespace std;
int main() {
// 函数指针的方式给 Lambda 表达式赋值
int(*p) (int a, int b) = [](int a, int b) -> int {
return a + b;
};
cout << p(10, 20) << endl;
cout << p(20, 30) << endl;
return 0;
}
可以简化一点,表达式后面的 -> int 可以不写,会自动判断返回类型。
int(*p) (int a, int b) = [](int a, int b) {
return a + b;
};
既然 C++11 出现了 auto ,实际上更推荐这么写(更简洁):
#include<iostream>
using namespace std;
int main() {
// auto 自动判断类型,使用起来很方便
// 并且前面不需要写参数
auto p = [] (int a, int b) {
return a + b;
};
cout << p(10, 20) << endl;
cout << p(20, 30) << endl;
return 0;
}
Lambda 应用
不使用 Lambda 写一个 +,-,*,/ 可能是这么写的:
#include<iostream>
using namespace std;
int add(int v1, int v2) {
return v1 + v2;
}
int sub(int v1, int v2) {
return v1 - v2;
}
int multiply(int v1, int v2) {
return v1 * v2;
}
int divide(int v1, int v2) {
return v1 / v2;
}
// 函数指针
auto exec(int v1, int v2, int(*func)(int, int)) {
return func(v1, v2);
}
int main() {
cout << exec(20, 10, add) << endl;
cout << exec(20, 10, sub) << endl;
cout << exec(20, 10, multiply) << endl;
cout << exec(20, 10, divide) << endl;
}
30
10
200
2
使用了 Lambda 后就变成这样了:
#include<iostream>
using namespace std;
// 函数指针
auto exec(int v1, int v2, int(*func)(int, int)) {
if (func == nullptr) return 0;
return func(v1, v2);
}
int main() {
cout << exec(20, 10, [](int v1, int v2) {return v1 + v2; }) << endl;
cout << exec(20, 10, [](int v1, int v2) {return v1 - v2; }) << endl;
cout << exec(20, 10, [](int v1, int v2) {return v1 * v2; }) << endl;
cout << exec(20, 10, [](int v1, int v2) {return v1 / v2; }) << endl;
}
外部变量捕获
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 值捕获
auto func = [a, b] {
cout << a << endl;
cout << b << endl;
};
a = 11;
b = 22;
// Lambda 只捕获了a,b的值,后面的外面的变化与他无关
func(); // 10 20
}
10
20
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 隐式捕获(值捕获)
auto func = [=] { // 使用 = 自动捕获用到的参数
cout << a << endl;
cout << b << endl;
};
a = 11;
b = 22;
func(); // 10 20
}
10
20
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// a是引用(地址)捕获,b是指捕获
auto func = [&a, b] { // 使用 = 自动捕获用到的参数
cout << a << endl;
cout << b << endl;
};
a = 11;
b = 22;
func(); // 11 20
}
11
20
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// a是值捕获,其余变量是地址捕获
auto func = [&, a] { // 使用 = 自动捕获用到的参数
cout << a << endl;
cout << b << endl;
};
a = 11;
b = 22;
func(); // 10 22
}
10
22
#include<iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 隐式捕获(值捕获)
auto func = [&] { // 使用 = 自动捕获用到的参数
cout << a << endl;
cout << b << endl;
};
a = 11;
b = 22;
func(); // 11 22
}
11
22
一张图总结如下。。。
mutable
#include<iostream>
using namespace std;
int main() {
int a = 10;
auto func = [a]()mutable {
cout << ++a << endl;
};
func(); //11
cout << a << endl; //10
}
11
10