12.7 用 using 幫型態取別名
競程整天跟 long long 打交道(上冊 2.9 之後你就知道為什麼),一題打十幾次、九個字母加一個空格,高手嫌煩,於是幫型態取別名:
using ll = long long; // 從此 ll 就是 long long
這行的意思是從此 ll 就是 long long 的另一個名字。ll 跟 long long 是同一個型態的兩個名字——不是新型態,就是綽號,跟本名隨時可以混用:
#include <bits/stdc++.h>
using namespace std;
using ll = long long; // 兩個競程最常見的別名
using pii = pair<int, int>;
int main() {
ll big = 1000000000000000000LL; // 等同 long long big = ...
cout << big << '\n';
vector<pii> v = {{3, 4}, {1, 2}};
cout << v[0].first << ' ' << v[1].second << '\n';
long long x = big; // 綽號與本名可混用,同一個型態
cout << x << '\n';
return 0;
}
執行結果:
1000000000000000000
3 2
1000000000000000000
pair<int, int> 縮成 pii 之後,vector<pii> 比 vector<pair<int, int>> 清爽得多——開場高手程式碼的第四行就是這一句。
兩件小事:
- 舊式寫法
typedef:老程式碼裡常見typedef long long ll;,效果完全相同——只是新舊語法的差異(新名字的位置不同)。自己寫建議用using:新名字在左邊、等號在中間,跟變數宣告同一個閱讀方向。 - 也有人寫
#define ll long long:能動,但它跟using是兩回事——#define是 12.9 的巨集,編譯前的純文字取代。詳見下面的對照。 - 跟
using namespace std;的關係:同一個關鍵字的不同用法。那句是「打開 std 命名空間」(你從第一支程式就在寫),本節是「取型態別名」——別混為一談。
¶為什麼不用 #define ll long long?
兩者都能讓你少打字,差別在誰做這件事:#define 是前置處理器在編譯之前做純文字取代——整份程式只要出現 ll 這個字就被換掉,它不認識作用域,也不管你把 ll 當成什麼在用。using 則是真的宣告一個型態別名,跟一般的宣告一樣遵守作用域。
三個本站實測的差別:
| 情境 | #define ll long long |
using ll = long long; |
|---|---|---|
想拿 ll 當變數名:int ll = 5; |
展開成 int long long = 5;,編譯錯誤 expected unqualified-id before '=' token |
可以,區域名稱把別名遮蔽掉而已 |
結構體裡想放個成員叫 ll |
編譯錯誤 declaration does not declare anything |
可以 |
| 寫在某個函式裡面 | 出了那個函式依然有效(一路影響到檔案結尾) | 出了函式就失效,符合一般宣告的直覺 |
ll 只有兩個字母,很容易跟別人的變數名或成員名撞在一起——而 #define 撞上去就是編譯錯誤,訊息還往往指向一個看起來毫無關係的地方。所以取型態別名一律用 using;#define 留給 12.9 真正需要文字取代的場合。
動手試試看:把 12.5 動手試試看的重新排列解答加上 using pii = pair<int, int>; 改寫一遍。行有餘力再試試別名疊別名:using vpii = vector<pii>; 也完全合法——然後想想,縮寫到這個程度,是省力還是已經在寫密碼了?