えびちゃんの日記

えびちゃん(競プロ)の日記です。

競技プログラマ向け C++17 機能紹介

競技プログラマ、どうせ #define しか使わなくないか

if の初期化文

if 文の中に初期化文を書けるようになります。 たとえば、よくある DP の例を挙げます。

if (dp[next] > dp[cur] + cost) {
  dp[next] = dp[cur] + cost;
  ...
}

これは次のように書けるようになります。

if (int tmp = dp[cur] + cost; dp[next] > tmp) {
  dp[next] = tmp;
  ...
}

うーーん、chmin を書いた方が楽かな(せめて #define じゃなくて関数テンプレートを使ってほしい)

tmp が if の外に漏れないので変なバグを防げたり、同じ式を書かないで済むのはうれしそう。

ja.cppreference.com

構造化束縛

pair や tuple からまとめて初期化できます。 たとえば Dijkstra 法で優先度つきキューから取り出すところを考えます。

priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
...
while (!pq.empty()) {
  int w = pq.top().first;
  int v = pq.top().second;
  ...
}

あるいは

while (!pq.empty()) {
  int w, v;
  tie(w, v) = pq.top();
  ...
}

これがこう書けるようになります。

while (!pq.empty()) {
  auto [w, v] = pq.top();
  ...
}

これはわりとよさそうみたいなとこない? Dijkstra 自体はぺたりされそうだけど。

ja.cppreference.com

クラステンプレートの実引数推定

vector などのテンプレート引数を省略できる局面があります。

vector<int> a(n, 0);

これをこう。

vector a(n, 0);

え、もしかして

vector a(n1, vector(n2, vector(n3, 0)));

みたいに書けるようになったりしますか? できますね、すごそう。 いや、えびちゃんは適当にテンプレートを使っちゃいます(14 で十分書けちゃうんですけど)。

auto a = make_vector({n1, n2, n3}, 0);

古いのだと地獄を書く必要があることで有名ですね。

vector<vector<vector<int>>> a(n1, vector<vector<int>>(n2, vector<int>(n3, 0)));

ja.cppreference.com

ja.cppreference.com

clamp

ある値 v区間 [lo, hi] を超えていたらその区間の最小値や最大値まで丸める処理ってたまにないですか? たまにありますね。

min(max(v, lo), hi)

これがこう書けます。

clamp(v, lo, hi)

#include <algorithm> ですね。

ja.cppreference.com

数学関数

lcm や gcd が #include <numeric> で使えます。 未定義動作には気をつけましょう。

ja.cppreference.com

ja.cppreference.com

あと hypot というのがあって、斜辺の長さを求められるのがあります。

hypot(x, y)  // sqrt(x*x + y*y)

これの三次元版が追加されます。

hypot(x, y, z)  // sqrt(x*x + y*y + z*z)

ja.cppreference.com

constexpr if

これはその手の人しか使わなさそう。

optional

これもどうかなぁ。ライブラリ整備勢がうれしくなることがあるのかも?

「この変数は int 型の何かを持っているかもしれないし無を持っているかもしれない」というのを表現できます。

適当な inf で番兵を置かずに、無にしておくことで「inf が小さすぎて WA だった」のような事故を防げそう? いや、場合分けが増えちゃうだけかなぁ。

未定義動作には気をつけましょう。

ja.cppreference.com

おわり?

にゃぁ。そのくらいですか? もっとある気もするかも。

en.cppreference.com

この辺を参照するといいかも。