メタプログラミングはかなりエキゾチックなトピックです。学ぶのは面白いです、それは強力なツールです、そして時々あなたはそれが役に立つと思うかもしれません。ただし、ツールボックスで最も頻繁に使用されるツールになることはありません。場合によっては、異なるプロパティを持つ一連の無関係な型にコードを作用させたいことがあります。そこでメタプログラミングが役立ちます。少し注意が必要ですが、引数の型が整数である場合にのみ使用できる関数のオーバーロードを記述できます。 、またはそれがポインタである場合、またはタイプX、Y、またはZのいずれかである場合(おそらくZの定数を無視します)。
それは本質的に型を使ったプログラミングです。通常、プログラムは2つの数値を取得して、3番目の数値を生成したり、数値が何らかの要件を満たしているかどうかを通知したりすることができます。メタプログラミングは、2つのタイプを取り、3番目のタイプを生成するか、タイプが何らかの要件を満たしているかどうかを通知します。そして、はい、それはおそらくライブラリ開発で主に役立ちます。しかし、繰り返しになりますが、ほとんどのコードはライブラリコードと見なすことができます。main()関数以外はすべてライブラリコードであると言えます。
通常、メタプログラミングを通じて問題を解決したい場合は、関連するBoostライブラリを使用して手間のかかる作業を行うことをお勧めします。Boost.TypeTraitsともちろんBoost.Mplは、あなたのために物事を本当に単純化することができます。しかし、それはあなたが知る必要のあるものではなく、あなたが頻繁に必要とする可能性のあるものでもありません。
ジェネリックプログラミングは関連しています(場合によっては、内部でメタプログラミングを使用して実際にジェネリックになることがあります。たとえば、標準ライブラリはメタプログラミングのタッチを使用して、生のポインターを有効なイテレーターに変換します。これは、「イテレーター」の概念がジェネリックであるために必要です) 、しかし完全に同じではありません。そしてそれははるかに広く使われています。
をインスタンス化するたびにstd::vector
、ジェネリックプログラミングを使用します。一連の値を処理するためにイテレータのペアを使用するたびに、ジェネリックプログラミングを使用します。ジェネリックプログラミングは、コードが可能な限りジェネリックであり、どのタイプが記述されていても機能する必要があるという考えにすぎません。std :: vectorは、「ICanBeContained」インターフェースを実装するために包含型を必要としません(Javaがコンテナークラスに格納するためにObjectからすべてを派生させる必要があることを覚えていますか?つまり、プリミティブ型はボックス化され、型の安全性が失われること。これは一般的ではなく、無意味な制限です。)
イテレータを使用してシーケンスを反復処理するコードは一般的であり、任意のタイプのイテレータ、またはプレーンポインタでも機能します。
ジェネリックプログラミングは非常に広く有用であり、多くの場合、OOPを大幅に置き換えることができます。(上記の例を参照してください。その制限を回避できるのに、インターフェイスを実装するために含まれている型を必要とするコンテナーを作成するのはなぜですか?)
多くの場合、OOPでインターフェースを使用する場合、実行時にタイプを変更することはできませんが(もちろん、それは時々発生します)、コンパイル時に別のタイプにスワップできるようにします(おそらく、本格的な実装を使用するのではなく、テスト中にオブジェクトをモックする)、または単に2つのクラスを分離するため。ジェネリックプログラミングは、インターフェースを定義して維持するという面倒な作業をしなくても、それを行うことができます。そのような場合、ジェネリックプログラミングは、より少ないコードを記述して維持する必要があることを意味し、より優れたパフォーマンスとより優れた型安全性を実現します。そうです、あなたは間違いなくジェネリックプログラミングに慣れているはずです。C++はあまり良いOOP言語ではありません。OOPに厳密に固執したい場合は、Javaまたは他のよりOOPに固定された言語に切り替える必要があります。C++ではOOコードを書くことはできますが、それが最善の解決策ではないことがよくあります。標準ライブラリのほぼ全体がOOPではなくジェネリックプログラミングに依存しているのには理由があります。標準ライブラリには、継承やポリモーフィズムはほとんどありません。彼らはそれを必要としませんでした、そしてコードはそれなしでより使いやすくそしてより強力になりました。
そして、他の質問に答えるために、はい、ジェネリックプログラミングはほとんど別のパラダイムです。テンプレートメタプログラミングはそうではありません。これは型システムを操作するためのかなり特殊な手法であり、少数の問題を解決するのに非常に優れています。パラダイムと見なされるには、はるかに一般的に有用であり、機能、OO、ジェネリックプログラミングなど、基本的にすべてに使用できるアプローチである必要があると思います。
xtoflは本当にそれを釘付けにしたと思います:ジェネリックプログラミングはあなたのコードをタイプに気づかないようにすることです。(std :: vectorは気にしないか、どのタイプが格納されているかを知る必要があります。それは機能します。)
一方、メタプログラミングは型の計算に関するものです。タイプT0とT1が与えられた場合、整数N0とN1が与えられた場合と同じように、タイプT2を定義できます。N0とN1の合計であるN2を定義できます。
Boost.Mplライブラリには、この明らかな例があります。通常のコードでは、整数N0、N1、およびN2がある場合、これら3つの値を含むstd::vectorを作成できます。次に、他のアルゴリズムを使用してインデックスを計算し、ベクトル内のその場所に格納されている値を抽出できます。
タイプT0、T1、およびT2が与えられると、これら3つのタイプを含むmpl::vectorを作成できます。これで、他のアルゴリズムを使用してコンパイル時にインデックスを計算し、ベクター内のその場所に格納されている型を抽出できます。