C++ テンプレート メタプログラミングを使用している場合、自分のコードの何が問題なのかを理解するのは非常に困難です。エラーメッセージを理解するのが苦手なだけかもしれませんが、私が知る限り、印刷ステートメントやブレークポイントを挿入して何が起こっているのかを理解することはできません。
何かがコンパイルされない理由を突き止めようとするとき、単にコードを手動で選択して、それが私に来ることを期待する以外に、どのようなヒントやアドバイスを提供できますか?
C++ テンプレート メタプログラミングを使用している場合、自分のコードの何が問題なのかを理解するのは非常に困難です。エラーメッセージを理解するのが苦手なだけかもしれませんが、私が知る限り、印刷ステートメントやブレークポイントを挿入して何が起こっているのかを理解することはできません。
何かがコンパイルされない理由を突き止めようとするとき、単にコードを手動で選択して、それが私に来ることを期待する以外に、どのようなヒントやアドバイスを提供できますか?
少なくとも STL については、より人間にわかりやすいエラー メッセージを出力するツールが利用可能です。http://www.bdsoft.com/tools/stlfilt.htmlを参照してください。
STL 以外のテンプレートの場合は、エラーの意味を理解する必要があります。それらを何十回も見た後、問題が何であるかを推測するのがより簡単になります. ここに投稿すると、誰かがそれを理解するのを手伝ってくれるかもしれません。
新しいコンパイラを使用してみることができます。Visual C++ 6.0 を使用している場合は、9.0 に切り替えると、コンパイラ エラーの有用性が大幅に向上します。
それ以外の場合、私のテクニックは通常、エラーを分離するまで、コードのできるだけ小さなセクションをテストすることです。これはおそらくテンプレート システムの最大の失敗です。それらをデバッグする賢明な方法はありません。
独自のコードでは、コンパイル時のアサートを自由に使用して、使用上の問題を診断しやすくします。
メタプログラミング言語で何か複雑なものを作るときは、BOOST_MPL_ASSERTマクロを複数回使用して、メタ実行のすべてのステップの結果を確認します。Boost.MPLライブラリはその点で非常に便利です。エラーが含まれていない可能性が高いため、そこからできるだけ多くのコードを使用することをお勧めします。
クラスに適切な特殊化が使用されているかどうかわからない場合は、名前空間で適切な特殊化を分離する傾向があります。スペシャライゼーションが有効であることを確認したら、それが選択されていることを確認する必要があります。そうでない場合は、代わりにどちらが選択されているかを確認する必要があります。次に、Boost.EnableIfを使用して、この誤って受け入れられた特殊化を選択プロセスから除外することをお勧めします。
最後になりましたが、STLfiltは非常に便利であり、ニーズにできるだけ合うように自分で変更することができます。
しかし、最も重要なことは、どこでもメタプログラミングを使用しないようにすることです。複雑なので、本当に必要なときだけ使ってください。
gcc を使用している場合、colorgccが少し役立つことがわかりました。色分けにより、警告、エラー、コンテキスト情報を頭の中で簡単に解析できます。
これは私が思うに役立つはずです。
http://www.bdsoft.com/tools/stlfilt.html
私自身は使用していません。しかし、それはあなたを助けるかもしれません。また、テンプレートとメタプログラムの経験が増えるにつれて、エラー メッセージに慣れることもできます。時々読むのが少し難しいかもしれません。しかし、彼らの狂気には論理があります。端末をできるだけ大きくして、読みながら頭の中で言っていることを翻訳してみてください。
どのコンパイラを使用していますか? 実際、VC8 と 9 は、読みやすいエラー メッセージを出力するのにかなり適しています。実行するにはまだ少し忍耐が必要ですが、それは可能であり、基本的にコールスタックと同等のコンパイル時を示しています。一番下から、エラーの原因となったテンプレートのインスタンス化と、テンプレートの引数は何でしたか? 次のレベルアップでは、インスタンス化されたテンプレートがトップレベルまで表示されます。もちろん、これは「出力」タブにのみ表示され、コンパイルが失敗した後に通常表示される「エラー」タブには表示されません。
原則は GCC でも似ていますが、最後に試してみたところ、少なくとも書式設定はやや読みにくかったです。しかし実際には、インスタンス化のスタックをトレースし、各レベルで、エラーを引き起こした型が見つかるまで、期待した型でインスタンス化されていることを確認する必要があります。
面倒ですが、実行可能です。必要なのは、忍耐とエラー メッセージを読む意欲だけです。:)
また、static_assert (または BOOST_STATIC_ASSERT) を自由に使用すると、健全性チェックが提供されるため、大いに役立ちます。
デバッグの場合、ある時点でメタプログラムを停止し、何らかの型計算の結果である型を表示することが役立つことがよくあります。これは次のように実現できます。
template <class T>
struct mp_debug : T::MP_DEBUG_FORCE_COMPILE_FAILURE {};
using Foo = int; // type to be inspected
// usage at namespace scope
template struct mp_debug<Foo>;
// usage at function scope
int main() {
mp_debug<Foo>{};
}
これにより、コンパイラは mp_debug の評価された型引数を示すコンパイル時エラーを出力します。
時間が経つにつれてそれに慣れますが、残念ながら、C ++の使用を計画している場合は、そうする必要があります。なぜなら、VC9のようないくつかのライブラリには良いエラーメッセージがありますが、GCCや他のコンパイラと言うように移動するとすぐに、メッセージは消えてしまいます。また、VC9でさえ、他の誰かが書いたライブラリや深夜に自分でエラーが発生した場合はあまり役に立ちません。Boostライブラリの中にはそれほど友好的ではないものもあります。エラーが発生したときにすべての作成者が問題を明確にするために苦労したわけではないという理由だけで、それは新しいライブラリ(エラーが最も多く、ヘルプが少ない傾向がある)ではさらに一般的です。
また、コードのあちこちで見られる素晴らしいSTATIC_ERRORSは、作者によって一般的に壊れている場所に配置され、作者が考えていなかった恐ろしいコーナーケースが常に存在することを覚えておく必要があります。たとえば、どこかでconstを見逃したためにエラーメッセージが表示されます。
ツールを使用すると、最初は役に立ちますが、長期的には傷つきます。また、この問題はC ++に固有のものであるため、すぐになくなることはありません。そして、これらのエラーの壁は、C++が使用されなくなるまで私たちにある可能性があります。したがって、ツールは、生き残るために必要なときに、歯を切るだけです。すぐにC++を終了する予定の場合は、お気軽にご利用ください。今日では、通常、400行のエラーメッセージを一目で理解できるので、目にははっきりとわかりますが、それはツールのおかげではありません。
すべて、特にC ++と同様に、経験とトレーニングが必要です。
回答がすでに示しているように、テンプレート コードには基本的に 2 種類の問題があります。
私は通常、コンパイル時のタイプ マジックを実行時のロジックから分離しようとします。これは、問題の原因 (タイプ 1 または 2) を見つけるのに役立ちます。これを実現する方法は、タイプ マジックに 1 つのテンプレート タイプを使用し、ランタイム機能をできるだけ少なくし、テンプレート タイプを使用するランタイム ロジックにプレーン タイプを 1 つ使用することです。
その後、他の回答、特に compile_time アサートに関する回答からのアドバイスに従うと、問題の原因を見つけやすくなります。
Templight : C++ テンプレート メタプログラム デバッガーおよびプロファイラー