0
@Raclamusi

これで効率爆上がり!C/C++の競プロ用テンプレートをmain関数の下に追いやる必殺技

はじめに

皆さんは競技プログラミングで「テンプレート」は使っていますか?
repchminmodpow など、よく使う処理を事前に用意したもののことです。
この記事では、C/C++で使える「テンプレート」1の記述方法について紹介します。

C/C++のテンプレートは邪魔!

テンプレートはとても便利です。コンテスト時に書くコードが少なくなり、解答スピードが速くなります。
実装方法を忘れてコンテスト中に調べ直す、なんてこともなくなります。

しかし、便利さを追い求めて様々な関数やクラスの追加を重ねるうちに、テンプレートが膨大な行数になってしまいがちです。
また、C/C++ではどうしても使うより先に宣言が必要です。すると、 main 関数はテンプレートの下に書かなくてはならず、いちばん下の main 関数にたどり着くまでのスクロールでイライラしてしまいます
さらに、参考にしようとあなたの提出コードを読もうとした人が、いつまでも続くテンプレートを見て読むのを諦めてしまうかもしれません。

ヘッダファイルに分割しようにも、AtCoderなどの競技プログラミングサイトではフォルダでまとめて提出するといったことができません。
なので、すべて1つのファイルに書く必要があります。

ん? ヘッダファイル? 1つのファイルに書く? …………!

必殺!「自身をインクルード」

私、ひらめいちゃいました。
提出ファイルにソースファイル兼ヘッダファイルになってもらって、提出ファイルに提出ファイルをインクルードすればいいのです!

「ちょっと何言ってるかわからない。」

まあ、一度見てみてください。

必殺技の使い方

必殺技を使うには、下のように書きます。
テンプレートの部分は、自分用に書き換えて使ってください。

#ifndef INCLUDED_MAIN
#define INCLUDED_MAIN

#include __FILE__  // このファイル自体をインクルード

int main()
{
    // 解答コード
}

#else  // INCLUDED_MAIN

// ↓テンプレート↓

#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define all(x) begin(x), end(x)
template <class T>
bool chmax(T &a, const T &b) {
    if (a < b) a = b; return a < b;
}
template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) a = b; return b < a;
}

// ↑テンプレート↑

#endif  // INCLUDED_MAIN

main 関数がテンプレートより上に来ています!
これでテンプレートをどれだけ増やしても、ファイルやリンクを開くとすぐに main 関数が読めます!

必殺技の解説

ポイントはプリプロセッサによる条件分岐です。インクルードガードと同じような方法を使っています。

#ifndef INCLUDED_MAIN

// ①

#else

// ②

#endif

最初の行の #ifndef の条件分岐で、 INCLUDED_MAIN マクロが定義されていないときは①のコードだけ読まれ、すでに定義されているときは②のコードだけ読まれます。

#define INCLUDED_MAIN
                   // INCLUDED_MAIN が定義されているので
#include __FILE__  // ←ここでは②だけ読まれる

そして、①の部分の最初に INCLUDED_MAIN を定義してから、自身をインクルードします。 __FILE__ は自身のファイル名2の文字列リテラルに展開される組み込みマクロです。
すると、先ほど解説した条件分岐で②の部分だけ読まれます。

ということは、①の部分はソースファイル、②の部分はヘッダファイルとして扱えます。
したがって、①の部分に main 関数を、②の部分にテンプレートを書けばいいのです。

これでテンプレートが main 関数の下にあってもコンパイルが通ります!

おわりに

これで問題を解く効率が少しはよくなると思います。3
C/C++使いの方はぜひご活用ください。


  1. C++のクラステンプレートや関数テンプレートの「テンプレート」ではないです。 

  2. 絶対パスの場合もあります。 

  3. タイトルの「爆上がり」は言い過ぎだと思います。 

0
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
Raclamusi
C++とJ言語が好きな高校生です。

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
Microsoft Igniteに参加してイベントに関する記事を投稿しよう!
~
ユーザーは見つかりませんでした