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