---
tags: books, note
---
# Others
## Pair
> 用途: 一個有`first`和`second`兩個元素的容器
> 使用時需要引入標頭檔`utility`或`algorithm`
要把兩個元素綁在一起的時候如果嫌麻煩不想自己刻就可以用`pair`代替
`pair`有內建定義用來比較的`less`函數,所以可以直接排序,不用多載`operator`,比較方便一點
### 用法
#### 宣告
```cpp
pair<first_type, second_type> p;
pair<first_type, second_type> p(a, b);
```
- `a`為型態為`first_type`的一變數
- `b`為型態為`second_type`的一變數
#### 存取
```cpp
p.first, p.second;
```
### 範例
```cpp=
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
vector<pair<int, int>> v{{2, 2}, {3, 1}, {2, 1}};
sort(v.begin(), v.end());
for (const auto& i : v)
cout << i.first << ' ' << i.second << endl;
return 0;
}
```
```
result:
2 1
2 2
3 1
```
### make_pair函數
```cpp
pair<first_type, second_type> p = make_pair(a, b);
```
功能同`pair`的建構元
---
###
## Range based for loop (since C++11)
> 用途: 將iterable的容器整個遍歷
### 用法
```cpp
for (range_declaration : range_expression) {
loop_statement
}
```
- `range_declaration`: 為一個變數,其型態要和`range_expression`內元素的型態保持一致或可轉換成一致
- `range_expression`: 為一個可迭代(iterable),或者說具有`begin`跟`end`的容器
- `loop_statement`: 可以為任何敘述、運算式
e.g.
```cpp=
vector<int> vec{1, 5, 4, 2, 3};
for (int i : vec)
cout << i << ' ';
```
這個程式碼的作用相等於
```cpp=
vector<int> vec{1, 5, 4, 2, 3};
for (size_t i = 0; i != vec.size(); i++)
cout << vec[i] << ' ';
```
由此可見當使用方式簡單時,
用Range based for loop的程式碼易讀性比較高,寫起來也比較簡潔
---
## Auto (since C++11)
> 用途: 自行判斷變數型態
e.g.
```cpp=
vector<pair<int, int>> vec;
auto copied_vec = vec;
```
相等於
```cpp=
vector<pair<int, int>> vec;
vector<pair<int, int>> copied_vec = vec;
```
再看一個極端一點的例子
e.g.
```cpp=
template<typename T>
void sort(__gnu_cxx::__normal_iterator<T*, vector<T>> l, __gnu_cxx::__normal_iterator<T*, vector<T>> r) {
//some code
}
int main() {
vector<int> v{1, 5, 3, 2, 4};
sort(v.begin(), v.end());
return 0;
}
```
等同於
```cpp=
void sort(auto l, auto r) {
//some code
}
int main() {
vector<int> v{1, 5, 3, 2, 4};
sort(v.begin(), v.end());
return 0;
}
```
---
## Lambda expression
> 又名Anonymous function, 匿名函數
當我們在自訂一些函數(e.g. `sort`)的比較函數時
常常會需要在外部先寫出來再去引用
如果用Lambda expression就可以在**需要用的地方進行定義**
lambda函式的形參表比普通函式的形參表多了3條限制:
1. 參數不能有預設值
2. 不能有可變長參數列
3. 不能有無名參數
### 用法
```cpp
[capture](parameters) mutable exception attribute -> return_type { function_body }
```
其中```mutable``` ```exception``` ```attribute``` 通常都用不到,可省
```cpp
[capture](parameters) -> return_type { function_body }
```
e.g.
```cpp=
[](int x, int y) -> int { return x + y; } // 指定回傳值型態為int
```
其中```return_type```在回傳值型態明確時可省,變成
```cpp
[capture](parameters) { function_body }
```
e.g.
```cpp=
[](int x, int y) { return x + y; } // 從return語句中隱式獲得的返回值類型
[](int& x) { ++x; } // 沒有return語句 -> lambda函數的返回值為void
```
`parameters`在沒有```return_type``` 或 ```mutable```, ```exception```, ```attribute``` 也可省
最簡化版:
```cpp
[capture] { function_body }
```
e.g.
```cpp=
[]() { ++global_x; } // 沒有參數,僅僅是訪問一個全局變量
[]{ ++global_x; } // 與前者相同,()可以被省略
```
- `capture`: 擷取列表,在lambda表達式中使用外部之變數都要經由擷取列表擷取,利用以下形式可以選擇要以值傳遞或是引用(參照)傳遞
- `parameters`: 參數,和一般函式的參數用法一樣,不過不能設初始值,也不能用`auto`代替(C++14以上可以)
- `return_type`: 回傳值型態
- `function_body`: 函式主體,可以是任何表達式
#### 擷取列表
```cpp
[] // 沒有定義任何變量,但必須列出空的方括號
[x, &y] // x是按值傳遞,y是按引用傳遞
[&] // 任何被使用到的外部變量都按引用傳入。
[=] // 任何被使用到的外部變量都按值傳入。
[&, x] // x按值傳入。其它變量按引用傳入。
[=, &z] // z按引用傳入。其它變量按值傳入。
```
### 實際使用
e.g.
```cpp=
inline bool cmp(const int& a, const int& b) {
return a > b;
}
int main() {
vector<int> v{1, 5, 4, 2, 3};
sort(v.begin(), v.end(), cmp);
return 0;
}
```
等同於
```cpp=
int main() {
vector<int> v{1, 5, 4, 2, 3};
sort(v.begin(), v.end(), [](const int& a, const int& b) {
return a > b;
});
return 0;
}
```
---
## I / O優化
C++的 `cin`/`cout` 相較於C的`printf`/`scanf`
基本上在一般情況下是慢蠻多的
所以需要一些**優化**來補足這個缺點
以下提供常見的優化方式供參考
### cin.tie + sync_with_stdio
這種最簡單,只要在`int main()`裡一開始放這兩行就能發揮作用
```cpp
cin.tie(nullptr);
ios::sync_with_stdio(false);
```
如果換行很多的時候可以在標頭檔下面加上`#define`
i.e.
```cpp=
#include <iostream>
#define endl '\n'
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
return 0;
}
```
:::info
> 更多的 I/O 優化可以參考 [$9^{th}$進階助教的 blog](https://happylearningcoding.blogspot.com/2020/04/c-io.html#more)
> [color=#4fff98][name=9th進階助教$][time=Sat, May 16, 2020 12:24 PM]
:::
---
## limits
有的時候我們會需要用到一些型態的最大最小值
像是`int`的最大$2^{31}-1$ aka $2147483647$之類的
那這時候就可以用`<limits>`裡的內建函式
i.e.
```cpp
numeric_limits<target_type>::max()
numeric_limits<target_type>::min()
```
- `target_type`: 需要求最大最小值的型態
那如果是字串大小的最大值,一般又會用另一種表示法
i.e.
```cpp
string::npos
```
這個常數代表的是`size_t`的 $-1$
不過`size_t`是一個無號整數,所以實際上等於$2^{32}-1$ aka $4294967295$
---
## 排版
#### 原則
- 每行對齊乾淨
- operator 前後加上 space
- 逗號前面不用 space, 後面要 space
- 大括號後要換行, 之後程式碼要縮排
- 小括號和大括號中間要一個空格
e.g.
```cpp=
int main() {
int tmp = 0, n;
cin >> n;
for (int i = 0; i < n; i++) {
tmp += i;
}
cout << tmp << endl;
return 0;
}
```
這樣的排版是不是很美觀呢?
舉個例子,$8^{th}$ 副班長,因為沒有排版習慣,去海高的時候被教授唸了一下 :poop:
總之,多看別人的 code 之後,寫的時候就會有排版的習慣了,排版是一個好的習慣,所以 space 不要太過節省哦!
:::info
> Sublime Text使用者可以參考[$9^{th}$進階教學的codebook](https://hackmd.io/@konchin/sublimeTutorial#附錄1-添加自動排版功能)
> [name=9th進階教學][time=Sat, May 16, 2020 12:30 PM]
:::
> [name=9th進階助教][time=Sat, May 16, 2020 12:43 PM]
---
## 一些技巧
### 輸出入by檔案
因為每次在測測資的時候都要一直複製貼上
而且輸出的東西又會跟輸入的東西混在一起
所以可以透過改變I/O stream來方便修改/存取

---
### 語法模板 + debug
懶人必備
```cpp!
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
#define F first
#define S second
#define FOR(i, a) for(ll i = 0; i < a; i++)
#define REP(i, a, b) for(auto i = a; i != b; i++)
#define ALL(x) x.begin(), x.end()
#define GET(i, x) get<i>(x)
#define mkp make_pair
#define pb push_back
#define debug(...) do{\
fprintf(stderr, "%s - %d : (%s) = ", __func__, __LINE__, #__VA_ARGS__);\
_DO(__VA_ARGS__);\
}while(0)
template<typename T> void _DO(T&&x){cerr << x << '\n';}
template<typename T, typename... A> void _DO(T&&x, A&&...As){cerr << x << ", ";_DO(As...);}
int main() {
cin.tie(nullptr), cout.tie(nullptr), ios::sync_with_stdio(false);
return 0;
}
```
> [color=#FF0000][name=9th教學顧問][time=Sun, June 21, 2020 22:14]
---
> [color=#2329d1][name=9th進階教學][time=Sat, May 16, 2020 11:57 AM]
---