うーん..C++テンプレートを深く理解していると言って、ジェネリックとそれらの違いを見て/感じないと言ったら、まあ、おそらくあなたは正しいでしょう:)
ジェネリックがテンプレートよりも優れている方法/理由を説明する多くの違いがあり、多くの違いをリストするなどですが、それはアイデアの核心とはほとんど無関係です。
アイデアは、より良いコードの再利用を可能にすることです。テンプレート/ジェネリックスは、実際の型のいくつかを抽象化する、ある種の高階クラス定義を構築する方法を提供します。
この用語では、それらの間に違いはなく、唯一の違いは、基盤となる言語とランタイムの特定の機能と制約によって強制されるものです。
ジェネリックスはいくつかの追加機能を提供すると主張する人もいるかもしれませんが(通常、オブジェクトのクラスツリーの動的なイントロスペクションについて話す場合)、C++のテンプレートに手動で実装できないものはほとんどありません。ある程度の努力を払えば、それらのほとんどは実装またはエミュレートできるため、「適切なジェネリック」と「実際のテンプレート」の区別としては適切ではありません。
他の人は、C++のコピーアンドペースト動作のおかげで利用できる最適化の潜在的な力が違いだと主張するでしょう。申し訳ありませんが、真実ではありません。JavaとC#のJITもそれを実行できますが、ほとんど実行できますが、非常にうまく実行できます。
ただし、Java / C#のジェネリックをC++のテンプレート機能の真のサブセットにすることができることが1つあります。そして、あなたもそれについて言及しました!
テンプレートの特殊化です。
C ++では、各特殊化は完全に異なる定義として動作します。
C ++では、template<typename T> Foo
T==intに特化したものは次のようになります。
class Foo<int>
{
void hug_me();
int hugs_count() const;
}
T==MyNumericTypeに特化した「同じ」テンプレートは次のようになります。
class Foo<MyNumericType>
{
void hug_me();
MyNumericType get_value() const;
void reset_value() const;
}
参考までに:これは単なる擬似コードであり、コンパイルされません:)
JavaとC#のジェネリックはどちらもそれを行うことができません。なぜなら、それらの定義では、すべてのジェネリック型の実体化が同じ「ユーザーインターフェイス」を持つことを示しているからです。
さらに、C++はSFINAEルールを使用します。テンプレートには、多くの「理論的に衝突する」スペシャライゼーションの定義が存在する可能性があります。ただし、テンプレートを使用する場合は、「実際に良い」ものだけを使用します。
上記の例と同様のクラスで、次を使用する場合:
Foo<double> foood;
foood.reset_value();
... "reset_value"が欠落しているため、最初の特殊化はコンパイルされないため、2番目の特殊化のみが使用されます。
ジェネリックでは、それを行うことはできません。可能なすべてのメソッドを持つジェネリッククラスを作成する必要があります。そうすると、実行時に内部オブジェクトが動的に検査され、使用できないメソッドに対して「実装されていない」または「サポートされていない」例外がスローされます。それは...ただひどいです。このようなことは、コンパイル時に可能になるはずです。
テンプレートの特殊化とSFINAEの実際の能力、影響、問題、および全体的な複雑さは、ジェネリックとテンプレートを真に差別化するものです。単純に、ジェネリックスは、特殊化が不可能であり、したがってSFINAEが不可能であるような方法で定義されます。したがって、メカニズム全体が逆説的にはるかに簡単/単純になります。
コンパイラーの内部に実装するのが簡単/簡単であり、非賢明な頭脳によって理解されることの両方。
Java / C#のジェネリックの全体的な利点には同意しますが、特殊化、インターフェイスの柔軟性、およびSFINAEルールが本当に恋しいです。ただし、正気のオブジェクト指向デザインに関連する重要なことを1つ言及しなければ、公平ではありません。タイプxxxのテンプレートの特殊化によって、クライアントAPIが実際に変更される場合は、おそらく別の名前を付けて、別のテンプレートを形成する必要があります。 。テンプレートで実行できるすべての追加機能は、ほとんどの場合、ツールセットに追加されました。これは、C ++では反映がなく、何らかの方法でエミュレートする必要があったためです。SFINAEは、コンパイル時のリフレクションの形式です。
したがって、違いの世界で最大のプレーヤーは、ランタイムの欠陥を隠すために適用されるホットフィックスの奇妙な(有益な)副作用に減少します。これは、ランタイムの内省がほぼ完全に欠如していることです:))
したがって、言語によって強制されるいくつかの任意のもの、またはランタイムプラットフォームによって強制されるいくつかの任意のもの以外に違いはないと言います。
それらはすべて高階クラスまたは関数/メソッドの形式であり、これが最も重要な機能であると思います。