C++(デフォルトテンプレート、特化テンプレート)をアセンブリの目で見る


【声明:著作権所有、転載歓迎、商業用途に使用しないでください.連絡ポスト:[email protected]
デフォルト関数はC++の基本的な特徴です.デフォルト関数の定義は簡単です.つまり、関数の入力パラメータまたはいくつかの入力パラメータについて、特定の数値がなければ、デフォルトのデータで置き換えます.呼び出し中に自分のデータを使用すると、デフォルトのデータは私たちが定義したデータで上書きされます.デフォルトの関数の例を次に示します.
int  add(int m, int n = 10)
{
	return m + n;
}
もし呼び出されたら、どんな違いがありますか?
262:      int p = add(2);
00401488   push        0Ah
0040148A   push        2
0040148C   call        @ILT+15(add) (00401014)
00401491   add         esp,8
00401494   mov         dword ptr [ebp-4],eax
263:      p = add(3, 4);
00401497   push        4
00401499   push        3
0040149B   call        @ILT+15(add) (00401014)
004014A0   add         esp,8
004014A3   mov         dword ptr [ebp-4],eax
上のコードから、データ2が単独で入力されると、コンパイラはデフォルトで10を入力します.もし負けたデータが3、4だったら、コンパイラはデフォルトのデータ10の代わりに4を使います.だから、コンパイラは私たちに中間の置換と判断の仕事をしてくれました.では、今日議論したデフォルトのテンプレートタイプに戻ると、どのような状況になりますか?例を作成できます.
template <typename type1, typename type2 = int>
class data
{
	type2 value;
public:
	data(type2 m): value(m) {}
	~data() {}
};
では、2番目のパラメータでデフォルトタイプintを使用していることがわかりますが、デフォルトタイプが使用できることをどのように証明しますか?次のテスト例を設計しました.
239:      data<int, int> m(2);
004013BD   push        2
004013BF   lea         ecx,[ebp-10h]
004013C2   call        @ILT+5(data<int,int>::data<int,int>) (0040100a)
004013C7   mov         dword ptr [ebp-4],0
240:      data<int> n(3);
004013CE   push        3
004013D0   lea         ecx,[ebp-14h]
004013D3   call        @ILT+5(data<int,int>::data<int,int>) (0040100a)
上のコードは、2つの一時変数を定義し、そのうち1つ目はmであり、入力タイプはintである.2番目の一時変数はnで、入力タイプはintとintです.デフォルトタイプがintであると前述したように、第1の一時変数mと第2の一時変数nの構造関数アドレスは同じであるべきである.では、実際に両者の構造関数は同じではないでしょうか.両者の関数アドレスを見ると,1つは0 x 00410 aであり,もう1つも0 x 00410 aであることが分かった.例は私たちの判断が正しいことを証明した.
上のデフォルトテンプレートの構造がわかりました.次に、特化テンプレートについてお話しします.特化テンプレートとはどういう意味ですか?実は複雑ではありません.テンプレートクラスが汎用テンプレートである以上、その中のデータ型は任意のデータ型であってもよいので、しかし、いくつかのデータ型は避けられない.(ポインタなど)では、いくつかの操作を細かく修正する必要がありますが、これらの小さな修正は元のテンプレート定義ではできません.では、どうすればいいですか.テンプレートクラス定義の名前と一致する形式を再定義するしかありませんが、形式には少し違いがあります.テストを作成してみましょう.
template <typename type>
class data
{
public:
	data() {printf("normal!
");} ~data() {printf("~normal!
");} }; template <> class data<int*> { public: data() {printf("point!
");} ~data() {printf("point!
");} };
のコードは、2つのクラステンプレートを定義します.しかし、両者の名前は同じであり、この2つのクラス定義の内容が実際には大きな類似性を持っていることを示している.1つ目の定義は標準テンプレートクラスの定義で、2つ目は少し複雑で、デフォルトのint*を使用します.特定のtypeタイプには使用されていないので、templateの後ろの内容は空です.では、この2つのクラスが正常に使用できるとどのように判断しますか?次の例を見てみましょう.
249:      data<int> p;
004013BD   lea         ecx,[ebp-10h]
004013C0   call        @ILT+45(data<int>::data<int>) (00401032)
004013C5   mov         dword ptr [ebp-4],0
250:      data<int*> q;
004013CC   lea         ecx,[ebp-14h]
004013CF   call        @ILT+35(data<int *>::data<int *>) (00401028)
251:  }
最初の関数のcallアドレスは0 x 0401032であり、2番目のアドレスは0 x 0401028であることが分かった.しかし、これは何も説明できません.2番目のアドレスも最初のテンプレートクラスが引用した可能性があります.私たちは各関数に従うべきです(実はここのアドレスはVCの下でジャンプアドレスです).
最初の変数の実際の入力関数は次のとおりです.
234:      data() {printf("normal!
");} 00401340 push ebp 00401341 mov ebp,esp 00401343 sub esp,44h 00401346 push ebx 00401347 push esi 00401348 push edi 00401349 push ecx 0040134A lea edi,[ebp-44h] 0040134D mov ecx,11h 00401352 mov eax,0CCCCCCCCh 00401357 rep stos dword ptr [edi] 00401359 pop ecx 0040135A mov dword ptr [ebp-4],ecx 0040135D push offset string "normal!
" (0042607c) 00401362 call printf (00401540) 00401367 add esp,4 0040136A mov eax,dword ptr [ebp-4] 0040136D pop edi 0040136E pop esi 0040136F pop ebx 00401370 add esp,44h 00401373 cmp ebp,esp 00401375 call __chkesp (004023b0) 0040137A mov esp,ebp 0040137C pop ebp 0040137D ret
では、2番目の変数は、同じように関数を追加する必要があります.
242:      data() {printf("point!
");} 00401430 push ebp 00401431 mov ebp,esp 00401433 sub esp,44h 00401436 push ebx 00401437 push esi 00401438 push edi 00401439 push ecx 0040143A lea edi,[ebp-44h] 0040143D mov ecx,11h 00401442 mov eax,0CCCCCCCCh 00401447 rep stos dword ptr [edi] 00401449 pop ecx 0040144A mov dword ptr [ebp-4],ecx 0040144D push offset string "point!
" (00426074) 00401452 call printf (00401540) 00401457 add esp,4 0040145A mov eax,dword ptr [ebp-4] 0040145D pop edi 0040145E pop esi 0040145F pop ebx 00401460 add esp,44h 00401463 cmp ebp,esp 00401465 call __chkesp (004023b0) 0040146A mov esp,ebp 0040146C pop ebp 0040146D ret
上の関数を見ると、両者が呼び出す構造関数が異なることがわかります.したがって、特化テンプレートは通常、特殊なデータ型のために用意されています.これにより,我々利用者はテンプレートを使用する際に何の心配もなく,各データ型処理の違いを無視できる.もちろん、特化テンプレートは特殊なモデルデータを考慮しているため、私たちのコードがより完成し、より丈夫になりました.テンプレートを設計するときに適切に多く使用することをお勧めします.
思考問題:
(1)テンプレートクラスの最初のtypeはデフォルトでよろしいですか?なぜそう考えるのですか?
(2)次のコードはvc 6.0とvc 2005でコンパイルできますか?なぜですか?私たちの設計コードについてどう思いますか?(互換性の面から考えることをお勧めします)
template <typename type>
class data
{
public:
	data() {printf("normal!
");} ~data() {printf("~normal!
");} }; template <typename type> class data <type*> { public: data() {printf("point!
");} ~data() {printf("point!
");} };

【予告:次の2つのブログはとても面白いです.再帰テンプレートとテンプレートのテンプレートの内容を紹介します】