【C++】C++11 新特性(auto,decltype,nullptr,快速遍历,【Lambda表达式详解】)

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章