💡 C++ の「奇妙な再帰テンプレートパターン(CRTP)」を理解する
📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに C++ のテンプレートには数多くの応用テクニックがありますが、その中でも「CRTP(Curiously Recurring Template Pattern:奇妙な再帰テンプレートパターン) 」は特にユニークで強力な手法です。 Boost をはじめとする有名ライブラリでも多用されており、C++ の表現力を大きく広げてくれます。 この記事では、CRTP の基本から実用例、さらには応用パターンまでを整理して解説します。 CRTP とは? CRTP の基本形は以下のようになります。 template <typename T> class Base { public: T& getDerived() { return static_cast<T&>(*this); } }; class Derived : public Base<Derived> { // Derived 自身を Base のテンプレート引数として渡す }; 一見すると「派生クラス Derived が、まだ完成していない自分自身を基底クラス Base に渡している」ように見えます。この“自己参照”こそが CRTP の特徴です。 コンパイラはこれを問題なく処理でき、基底クラスはコンパイル時に派生クラスの型情報を知ることができます。 実用例:比較演算子の自動生成 C++ では == や < などの比較演算子を定義するのはよくある作業ですが、すべてを個別に書くと冗長になりがちです。 CRTP を用いると、基底クラスに「共通の比較演算子」をまとめ、派生クラスは最小限の実装だけで済ませられます。 基底クラス template <typename Derived> class Comparable { public: bool operator==(const Derived& other) const { return static_cast<const Derived*>(this)->equalsImpl(other); } bool operator!=(const Derived& other) const { return !(*this == other); } bool operator<(const Derived& other) const { return static_cast<const Derived*>(this)->lessImpl(other); } bool operator>(const Derived& other) const { return other < *this; } bool operator<=(const Derived& other) const { return !(*this > other); } bool operator>=(const Derived& other) const { return !(*this < other); } }; 派生クラス例 class Point : public Comparable<Point> { public: Point(int x_val, int y_val) : x(x_val), y(y_val) {} bool equalsImpl(const Point& other) const { return x == other.x && y == other.y; } bool lessImpl(const Point& other) const { return (x != other.x) ? (x < other.x) : (y < other.y); } private: int x, y; }; これで ==, !=, <, >, <=, >= がすべて利用可能になります。 ...