ここから興味深い記事/スレッド/ディスカッションを読んだところ、次の質問がありました。
- Java/C#ジェネリックの制限は何ですか?
- Java/C# ジェネリックでは不可能で、C++ テンプレートで可能なことは何ですか?
編集 1 Eric Lippertによるその他の推奨質問
- C# ジェネリックでは可能で、C++ テンプレートでは不可能なパターンは何ですか?
- C# の真のジェネリック型と Java の型消去ジェネリック型の違いは何ですか?
ここから興味深い記事/スレッド/ディスカッションを読んだところ、次の質問がありました。
編集 1 Eric Lippertによるその他の推奨質問
まず、このテーマに関する私の 2009 年の記事をお読みください。
C++ テンプレートと C# ジェネリックの主な違いは、C++ テンプレートはテンプレートの作成時にコードを実際に完全に再コンパイルすることです。C++ アプローチの長所と短所は多数あります。
PRO: 「型引数 T には加算演算子が必要」などの制約を効果的に作成できます。コードに相互に追加された 2 つの T が含まれている場合、追加を許可しない型引数でテンプレートを構築すると、テンプレートはコンパイルされません。
CON: 「型引数 T には加算演算子が必要です」のような文書化されていない制約を誤って作成する可能性があります。
C#では、ユーザーに役立つ制約を指定する必要がありますが、使用できる制約は、インターフェイス、基本クラス、値と参照型の制約、および既定のコンストラクターの制約など、ごく一部に限定されます。
PRO: セマンティック分析は、2 つの異なる構造で完全に異なる場合があります。あなたがそれを望むなら、それは素晴らしいことです。
CON: セマンティック分析は、2 つの異なる構造では完全に異なる可能性があります。あなたがそれを望まないなら、それは起こるのを待っているバグです.
C# では、型が何回構築されてもセマンティック分析は 1 回行われるため、実際に提供される型引数だけでなく、制約を満たす型引数を操作する必要があります。
PRO: まさに必要な構造のコードのみを生成します。
CON: 使用するすべての構造のコードを生成します。
テンプレートによって codegen が大きくなる可能性があります。C# では、ジェネリック型の IL が 1 回生成されると、実行時にプログラムが使用するすべての型に対してジッターが codegen を実行します。これにはわずかなパフォーマンス コストがかかりますが、ジッターが実際にはすべての参照型引数に対して 1 回だけコードを生成するという事実によって多少軽減されます。したがってList<object>
、List<string>
ジットされたコードは一度だけ生成され、両方に使用されます。対照的に、コードを 2 回 jit しますList<int>
。List<short>
PRO: テンプレート ライブラリを使用すると、ソース コードがすぐそこにあります。
CON: テンプレート ライブラリを使用するには、ソース コードが必要です。
C# では、ジェネリック型はファースト クラスの型です。それらをライブラリに貼り付ければ、ソース コードを出荷しなくても、そのライブラリをどこでも使用できます。
そして最後に:
PRO: テンプレートは、テンプレートのメタプログラミングを許可します。
短所: テンプレートのメタプログラミングは、初心者にとって理解しにくいものです。
短所: テンプレート システムでは、一般的なシステムで非常に単純なタイプ トポロジを実際に許可していません。
たとえば、C++ で次のようなことを行うのは難しいと思います。
class D<T>
{
class S { }
D<D<T>.S> ds;
}
C# ジェネリックでは、問題ありません。実行時に、型はすべての参照型引数に対して1 回だけ作成されます。
しかし、C++ テンプレートでは、 があるとどうなりますD<int>
か? 内部型は type のフィールドを構築するD<D<int>.S>
ため、その型を構築する必要があります。しかし、その型は型のフィールドを構築しますD<D<D<int>.S>.S>
...など、無限に続きます。
C++ のようないくつかのトリックを行うことができないため、Java ジェネリックは制限されています。
ここでの主張を証明するために、Java のテンプレートだけでは再現できない C++ の例を示します。
ポリシーベースのプログラミングは、(テンプレート化された) クラスの使用を、コンパイル時の継承で他の (可能な) テンプレート化されたクラスに制限する方法です。
コンパイル時のジェネリックとランタイムのジェネリックの違いは何ですか?
取り決めは、コンパイラがクラス/テンプレートの可能な実行時の動作についてすべてを知っているため、C#/Java/実行環境/コンパイラでは(現在)不可能な大幅な最適化を行うことができるということです。
これのもう 1 つの利点は、テンプレートの組み合わせの開始が有効であることをコンパイラが保証できることです。つまり、プログラマーがテンプレートを使用して新しいオブジェクトを開始したい場合に、Java/C# のように実行時エラーが発生する可能性はありません。無効な組み合わせ。
C++ ジェネリックの欠点は何ですか?
欠点は、テンプレートの読み取り、理解、およびデバッグが非常に複雑になる可能性があることです。これが (おそらく) Java 開発者が言語にそのような野獣を持ちたくなかった理由の 1 つです。
C++ では、他のテンプレートをテンプレート パラメーターとして使用できますが、これは C#/Java では不可能であり、テンプレート メタプログラミングのような洗練されたトリックを可能にします。