C++のテンプレートについて2つの質問があります。単純なリストを作成し、それをプログラムで使用して、さまざまなオブジェクトタイプ(A *、B * ... ALot *)へのポインターを格納するとします。私の同僚は、実際にはすべてのポインターのサイズが同じであっても、タイプごとに専用のコードが生成されると言っています。
はい、これは両方の関数を作成することと同じです。
一部のリンカーは、同一の機能を検出し、それらを排除します。一部のライブラリは、リンカーにこの機能がないことを認識しており、共通コードを1つの実装に分解し、共通コードの周りにキャストラッパーのみを残します。つまり、スペシャライゼーションはstd::vector<T*>
すべての作業を転送std::vector<void*>
し、途中でキャストを行う場合があります。
現在、comdatフォールディングはデリケートです。同じと思われる関数を作成するのは比較的簡単ですが、同じではなくなるため、2つの関数が生成されます。おもちゃの例として、を使用してタイプ名を出力することができますtypeid(x).name()
。現在、関数の各バージョンは区別されており、削除することはできません。
場合によっては、実行時のプロパティが異なると考えてこのようなことを行うことがあります。そのため、同じコードが作成され、同じ関数が削除されます。ただし、スマートC ++コンパイラは、ユーザーが何をしたかを理解し、 as-ifルールを使用してコンパイル時のチェックに変換し、実際には同一ではない関数が同一として扱われるのをブロックします。
これが本当なら、誰かが私に理由を説明できますか?たとえば、Javaのジェネリックは、C++のポインタのテンプレートと同じ目的を持っています。ジェネリックスは、コンパイルごとの型チェックにのみ使用され、コンパイル前に削除されます。そしてもちろん、すべてに同じバイトコードが使用されます。
いいえ、そうではありません。std::function<void()>
ジェネリックスは、呼び出し可能なオブジェクトを格納するために行うことなど、型消去のC++手法とほぼ同等です。C ++では、型消去はテンプレートを介して行われることがよくありますが、テンプレートのすべての使用が型消去であるとは限りません。
本質的に型消去されていないテンプレートでC++が行うことは、Javaジェネリックでは一般的に不可能です。
C ++では、テンプレートを使用して型消去されたポインターのコンテナーを作成できstd::vector
ますが、それはできません。実際のポインターのコンテナーが作成されます。これの利点は、のすべての型チェックがstd::vector
コンパイル時に行われるため、実行時チェックをstd::vector
行う必要がないことです。安全な型消去には、実行時型チェックとそれに関連するオーバーヘッドが必要になる場合があります。
2番目の質問は、charとshortの専用コードも生成されるかどうかです(両方とも同じサイズであり、特殊化されていないことを考慮して)。
それらは異なるタイプです。char
orの値で動作が異なるコードを書くことができshort
ます。例として:
std::cout << x << "\n";
xがaの場合、これは値が--であるshort
整数を出力します。これは、に対応する文字を出力します。x
x
char
x
現在、ほとんどすべてのテンプレートコードはヘッダーファイルに存在し、暗黙的にinline
です。ほとんどinline
の人がそれが何を意味すると思うかを意味するわけではありませんが、コンパイラがコードを呼び出し元のコンテキストに簡単に引き上げることができることを意味します。
これが何か違いを生むのであれば、私たちは組み込みアプリケーションについて話しているのです。
実際に違いを生むのは、特定のコンパイラとリンカ、およびそれらがアクティブにしている設定とフラグです。