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