C++ で見た最もクールなメタプログラミングの例は何ですか?
C++ で見たメタプログラミングの実用的な用途は何ですか?
10 に答える
個人的には、 Boost.Spiritはメタプログラミングの非常に素晴らしい例だと思います。これは、C++ 構文を使用して文法を表現できる完全なパーサー ジェネレーターです。
メタ プログラミングの最も実用的な使い方は、実行時エラーをコンパイル時エラーに変えることです。
例: インターフェイス IFoo を呼び出しましょう。私のプログラムの 1 つは、IFoo (非常に複雑な継承階層) への複数のパスを持つ COM オブジェクトを処理していました。残念ながら、基礎となる COM オブジェクトの実装は、IFoo への複数のパスがあることを認識していませんでした。彼らは、それが常に一番左のものであると想定していました。そのため、彼らのコード内では、次のパターンが非常に一般的でした
void SomeMethod(IFoo* pFoo) {
CFooImpl *p = (CFooImpl)pFoo;
}
ただし、2 番目の IFoo により、結果の "p" ポインターが完全に無効になりました (多重継承は危険です)。
長期的な解決策は、COM オブジェクトの所有者にこの問題を修正してもらうことでした。短期的には、常に正しい IFoo を返すようにする必要がありました。QI を使用し、IFoo への暗黙的なキャストを回避することで、適切な IFoo があることを保証できました。そこで、新しい CComPtr<> 実装を作成し、次のオーバーライドを equal メソッドに追加しました。
template <typename T>
CComPtr<T>& operator=(const T* pT) {
// CComPTr Assign logic
}
template <>
CComPtr<IFoo> operator=<IFoo>(const IFoo* pT) {
COMPILE_ERROR();
}
これにより、IFoo に暗黙的にキャストしたすべての場所がすぐに明らかになりました。
実用的ではありませんが (おそらくコンパイラのテストを除いて)、metatraceはコンパイル時のような画像を生成する Whitted-Style (つまり、再帰的で決定論的) レイ トレーサーです。
コードのより複雑な部分は、 Fixp.hhで確認できます。これには、Heron メソッドを使用した固定小数点 sqrt の実装が含まれています。または、光線/球の交差計算を示すsphere.hhがあります。
Blitz++は、テンプレートを使用していくつかの印象的なことを行います (たとえば、読み取り可能な 1 行のコードを多次元配列の一連のループに変換し、最適なトラバーサル順序に自動的に最適化できます)。
最もクールなメタプログラミングの例: コンパイラをだまして素数のリストを計算させます。あまり実用的ではありませんが、印象的です。
実用的な用途の 1 つは、コンパイル時の assert ステートメントです。つまり、ブール条件が満たされない場合にコンパイル エラーを引き起こします。
Boost.Lambda、Boost.Function、Boost.Bind、およびそれらがすべてシームレスに連携する方法について説明する必要があります。それらは非常に洗練されたインターフェイスを提供し、実際には関数型プログラミング用に構築されていない言語で関数型プログラミングを可能な限り簡単にします。
luabind は非常にクールな実用的な例であり、C++ クラスを lua にバインドするための非常に優れたバインド DSL です。
少し前に質問を投げかけました: C++ Runtime Knowledge of Classesと、StackOverflow ユーザー "Denice" から返された回答は、Web サイトMeatspace: C++ runtime class registrationへの URL でした。
これは、テンプレートを使用して、すべて基本クラスから派生したオブジェクトをインスタンス化するための非常に優れた方法だと思います。そのため、10 個の C++ ファイルがある場合、すべてのファイルの末尾に AUTO_REGISTER_BASE() を追加するだけで済み、すべてがすべての場合完了してリンクすると、それを作成したクラス/ファイルのみが登録されるため、実行時に利用可能なさまざまなクラスを切り替えることができ、利用できないクラスは登録されないため、誤って呼び出されることはありません。
イベント通知を行うには、OS に依存するさまざまな方法 (select()、kqueue()、/dev/epoll、Solaris には独自の poll() があります) があり、すべてのクラス ファイルをただし、Makefile が実行された OS によっては、特定のもののみがコンパイルされます。実行時にどれが利用可能かを知る方法が必要で、ライブラリを使用するプログラマーが好みを選択する方法が必要でしたが、それが利用できない場合は、プラットフォームにとって最も論理的な意味を持つものを使用するだけです (ウェイトが割り当てられています)。
上記のコードは、いくつかの大きな変更を加えてこの目標を達成するのに役立ちましたが、それでもなお役に立ちました!