C++ InsightsはClangベースのソース・ツー・ソース変換ツールであり、公式の目的は、通常意図的に裏側で行われている処理——プロジェクトの表現を借りれば「コンパイラが我々のために行う魔法」——を可視化することにある。アセンブリやASTダンプを出力するのではなく、C++のスニペットをC++言語そのものに書き換えるため、コンパイラの内部下限処理を馴染みのある文法で読める形で示す。

C++ Insightsプロジェクトロゴ
C++ Insightsのロゴ。Clangベースのソース・ツー・ソースツールを示す。github.com

冒頭段落はC++ InsightsをClangベースの変換ツールとして紹介し、その目的はコンパイラの背後での下限処理を可視化すること。ロゴは記述対象のプロジェクトを識別する。

动机はC++の教え方とデバッグの在り方の間にあるギップにある。ClangはASTダンプを出力でき、Compiler Explorerのようなツールはコンパイラが生成するアセンブリを示せる。しかしどちらの出力もC++ではなく、プロジェクトの著者はそれらに親しみを感じられなかったと語る。学生にC++を教えるとき、ASTを示して「全てそこにある」と断言するだけでは不十分だった。C++ Insightsはそのギップを埋めるために書かれた。

著者のアンドレアス・フェルティヒは2017年にC++11、C++14、C++17の新機能——ラムダ、範囲ベースforループ、構造化束縛——を学ぶうちにこの作業を始め、最初はスライドとビデオで発表した。その後、Clangベースのツールを書き、範囲ベースforループをコンパイラ内部版に変換する処理を構造化束縛とラムダにも拡張した。プロジェクトは初期の対象を超え、現在では演算子の呼び出し箇所やコンパイラが挿入するキャストの箇所を示し、`auto`や`decltype`の裏にある型を推定できる。

ツールの定番例は小さなクラス階層である。以下の入力に対し:

class Base { }; class Derived : public Base { }; int main() { Derived d; Derived d2 = d; d2 = d; Base& b = d; }

C++ Insightsは以下を出力する:

class Base { public: // inline constexpr Base() noexcept = default; // inline constexpr Base(const Base&) noexcept = default; // inline constexpr Base& operator=(const Base&) noexcept = default; }; class Derived : public Base { public: // inline constexpr Derived() noexcept = default; // inline constexpr Derived(const Derived&) noexcept = default; // inline constexpr Derived& operator=(const Derived&) noexcept = default; }; int main() { Derived d; Derived d2 = Derived(d); d2.operator=(d); Base& b = static_cast<Base&>(d); return 0; }

andreasfertig/cppinsightsのGitHubリポジトリヘッダー
プロジェクトのGitHubリポジトリヘッダー。ツールの名称と『コンパイラの視点でソースコードを見る』というタグラインを掲げる。github.com

可用性段落はコマンドラインツール、cppinsights.ioウェブサービス、エディタインテグレーション、Homebrew公式を列挙する。リポジトリヘッダーは読者をGitHub上のプロジェクトホームに誘う。

出力は元のソースが隠す二つを明らかにする。第一に、コンパイラは`Base`と`Derived`の両方に特殊メンバ関数——デフォルトコンストラクタ、コピーコンストラクタ、コピー代入演算子——をそれぞれ`inline constexpr`と`noexcept`付きで提供する。第二に、`main`内の暗黙的操作は明示的に書き換えられる:コピー`Derived d2 = d`は明示的な構築`Derived(d)`に、代入`d2 = d`は明示的なメンバ呼び出し`d2.operator=(d)`に、参照束縛`Base& b = d`は明示的なアップキャスト`static_cast<Base&>(d)`になる。

同じ仕組みが著者が当初対象にした機能にも適用される。範囲ベースforループはループがデサグアーする明示的形式に書き換えられる。ラムダはコンパイラ生成のクロージャ型とその`operator()`を示すように書き換えられる。`auto`や`decltype`の背後の型はそのまま表示される。目標は一貫してコンパイル可能なコードを生成することだが、プロジェクトは全ての場面で可能とは限らないと註している。

C++ Insightsはコマンドラインツール、cppinsights.ioのウェブサービス、Vim・Neovim・Visual Studio Code用のインテグレーション、macOSでのHomebrew公式フォームとして利用できる。コマンドライン呼び出しはソースファイルと標準フラグを取る。例:`insights <YOUR_CPP_FILE> -- -std=c++17`。システムインクルードパスはバイナリビルド時のコンパイラからハードコードされ、補助スクリプト`scripts/getinclude.py`がコンパイラからそれらを収集する。デフォルトパスにないカスタムGCCインストールには、STLの場所を指す`--gcc-toolchain`引数が必要。

プロジェクトの文書にはいくつかの注意書きがある。著者は「全て正しくできると主張するわけではない」と述べている。C++20のような新規標準の機能サポートは文書作成時点で進行中だった。ツールはClangとそのAST理解に基づくため、出力はそのパーサのコードモデルを反映する。ウェブサービスは最新Clangリリースを密接に追うが、Windows向けClangビルドの困難さからそのバージョンはしばしば数ヶ月遅れる。

唯一の実質的情報源がプロジェクト自身のリポジトリページであるため、上記の全ての主張はプロジェクト文書に帰属するものであり、独立検証によるものではない。意味のある不明点には、ウェブサービスが現在動かす正確なClangバージョン、C++20以降の機能サポートの完全性、文書に列挙されていないエッジケースで書き換え出力がどれだけ忠実にコンパイルされるかが含まれる。ツールを直接試したい読者には、cppinsights.ioのウェブサービスはインストール不要。