c++におけるテンプレートの実装(テンプレートクラスとテンプレート関数)
[TOC]
かたわく
交換関数を実装すると、次のように書くことができます.
ここでは2つの整数しか交換できません.2つの文字交換を実現する必要がある場合は、関数を書き直す必要がありますが、2つのコードには同じ部分がたくさんあります.これは面倒ではありません.コードを1部書くだけで異なるタイプの交換を実現できるなら、素晴らしいのではないでしょうか.はい、このコンパイラは私たちに設計してくれました.これはいわゆる汎用プログラミングです.テンプレートは汎用プログラミングの基礎であり,汎用プログラミングとはタイプに関係のない論理コードを記述し,多重化する方式である.
一、テンプレート関数
テンプレート関数のフォーマット:
template戻りタイプ関数名(パラメータリスト){...}
テンプレートパラメータの暗黙的インスタンス化
複数のタイプの交換が可能かどうかを確認し、テスト結果を確認します.
これがテンプレート関数の実装です.もちろん、なぜ関数が1つで済むのか知りたいです.実際には最下位で関数の再ロードが実現されており,アセンブリコードに移動すると分かる.
下位層では、Swap関数を呼び出すたびにスタックフレームが確立され、スタックフレームが確立されるたびに、パラメータのタイプが異なり、スタックフレームが確立されるのも異なることがわかる.テンプレートを使用すると、コンパイラはコンパイル前に行われる推論プロセスを行います.推論すると、コンパイラは、伝達パラメータのタイプに応じて対応する関数をインスタンス化(
時々私たちはこのような奇抜な問題に直面するかもしれません.
このように呼び出すと
テンプレートパラメータ表示のインスタンス化
これは、指定されたインスタンス化タイプ
二、テンプレート類
テンプレートクラスのフォーマット
c++でシーケンステーブルとチェーンテーブルを書き始める前に、私たちはそうでした.
このようにシーケンステーブルとチェーンテーブルを定義しますが、次のような大きな問題があります.
1つのプログラムで2つの異なるデータ型シーケンステーブルとチェーンテーブルを使用する場合、各タイプが1つのタイプを定義しない限り、完了できません.
かたわく
交換関数を実装すると、次のように書くことができます.
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
ここでは2つの整数しか交換できません.2つの文字交換を実現する必要がある場合は、関数を書き直す必要がありますが、2つのコードには同じ部分がたくさんあります.これは面倒ではありません.コードを1部書くだけで異なるタイプの交換を実現できるなら、素晴らしいのではないでしょうか.はい、このコンパイラは私たちに設計してくれました.これはいわゆる汎用プログラミングです.テンプレートは汎用プログラミングの基礎であり,汎用プログラミングとはタイプに関係のない論理コードを記述し,多重化する方式である.
。
一、テンプレート関数
テンプレート関数のフォーマット:
template
class, typename, 。
さっきのSwap関数はテンプレート関数でできます.テンプレートパラメータの暗黙的インスタンス化
template
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
複数のタイプの交換が可能かどうかを確認し、テスト結果を確認します.
これがテンプレート関数の実装です.もちろん、なぜ関数が1つで済むのか知りたいです.実際には最下位で関数の再ロードが実現されており,アセンブリコードに移動すると分かる.
int main()
{
00394D30 push ebp
00394D31 mov ebp,esp
00394D33 sub esp,114h
00394D39 push ebx
00394D3A push esi
00394D3B push edi
00394D3C lea edi,[ebp-114h]
00394D42 mov ecx,45h
00394D47 mov eax,0CCCCCCCCh
00394D4C rep stos dword ptr es:[edi]
00394D4E mov eax,dword ptr [__security_cookie (039A000h)]
00394D53 xor eax,ebp
00394D55 mov dword ptr [ebp-4],eax
int a1 = 1, a2 = 2;
00394D58 mov dword ptr [a1],1
00394D5F mov dword ptr [a2],2
Swap(a1, a2);
00394D66 lea eax,[a2]
00394D69 push eax
00394D6A lea ecx,[a1]
00394D6D push ecx
00394D6E call Swap (039137Ah)
00394D73 add esp,8
char c1 = 5, c2 = 6;
00394D76 mov byte ptr [c1],5
00394D7A mov byte ptr [c2],6
Swap(c1, c2);
00394D7E lea eax,[c2]
00394D81 push eax
00394D82 lea ecx,[c1]
00394D85 push ecx
00394D86 call Swap (0391375h)
00394D8B add esp,8
double d1 = 1.222, d2 = 2.011111111111;
00394D8E movsd xmm0,mmword ptr [__real@3ff38d4fdf3b645a (0397BD0h)]
00394D96 movsd mmword ptr [d1],xmm0
00394D9B movsd xmm0,mmword ptr [__real@400016c16c16c072 (0397BD8h)]
00394DA3 movsd mmword ptr [d2],xmm0
Swap(d1, d2);
00394DA8 lea eax,[d2]
00394DAB push eax
00394DAC lea ecx,[d1]
00394DAF push ecx
00394DB0 call Swap (039137Fh)
00394DB5 add esp,8
return 0;
00394DB8 xor eax,eax
}
下位層では、Swap関数を呼び出すたびにスタックフレームが確立され、スタックフレームが確立されるたびに、パラメータのタイプが異なり、スタックフレームが確立されるのも異なることがわかる.テンプレートを使用すると、コンパイラはコンパイル前に行われる推論プロセスを行います.推論すると、コンパイラは、伝達パラメータのタイプに応じて対応する関数をインスタンス化(
)してコンパイルしています.たとえば、template // class typename
void Swap(T1& x,T2& y)
{
T1 tmp = x;
x = y;
y = tmp;
}
時々私たちはこのような奇抜な問題に直面するかもしれません.
template< class T>
const T Add(T& x,T& y)
{
return x+y;
}
このように呼び出すと
Swap(1,1.2302102);
、コンパイラはどのようにインスタンス化されますか?テンプレートパラメータ表示のインスタンス化
これは、指定されたインスタンス化タイプ
Add Add(1,5.222222);
(1.5.222222)を表示しなければならないことに関する.これでさっきの問題を解決することができます.二、テンプレート類
テンプレートクラスのフォーマット
template
class
{ ... };
c++でシーケンステーブルとチェーンテーブルを書き始める前に、私たちはそうでした.
typedef int Datatype;
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
Datatype _data;
}ListNode;
このようにシーケンステーブルとチェーンテーブルを定義しますが、次のような大きな問題があります.
1つのプログラムで2つの異なるデータ型シーケンステーブルとチェーンテーブルを使用する場合、各タイプが1つのタイプを定義しない限り、完了できません.
<double>
typedef int Datatype; // int
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode _prev;
struct ListNode _next;
Datatype _data;
}ListNode;
typedef char Datatype; // char
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
Datatype _data;
}ListNode;
, , 。
template
class Vector
{
public:
Vector():_first(NULL),_finish(NULL),_endofstorge(NULL)//
{}
~Vector()//
{
delete[]_first;
_first = _finish = _endofstorge = NULL;
}
Vector(const Vector& v)//
:_first(NULL)
,_finish(NULL)
,_endofstorge(NULL)
{
int len = v._finish - v._first;
_first = _finish = new T[len];
T* start = v._first;
while(start != v._finish)
{
*(_finish) = *start;
++_finish;
++start;
}
_endofstorge = _first+len;
}
Vector& operator=(Vector& v) //
{
delete[]_first;
Vector v1(v);
swap(_first ,v1._first);
swap(_finish , v1._finish);
swap(_endofstorge , v1._endofstorge);
return *this;
}
void PushBack(const T& x) //
{
if(_finish == _endofstorge)
Expand(Capacity()*2+1);
_first[Size()] = x;
++_finish;
}
void PopBack()//
{
Erase(Size()-1);
}
void Expand(size_t n) //
{
int size = Size();
if(n>Capacity())
{
T* tmp = new T[n];
for (int i = 0;i
:
void VectorTest()
{
Vector v;
v.PushBack(1);
v.PushBack(2);
v.PushBack(3);
v.PushBack(4);
v.PushBack(5);
v.PushBack(6);
v.PushBack(7);
PrintVocter(v);
Vector v1;
v1.PushBack("hello");
v1.PushBack("world !");
v1.PushBack("i");
v1.PushBack("love");
v1.PushBack("you");
PrintVocter(v1);
}
#ifndef __LIST_H__
#define __LIST_H__
#include
#include
using namespace std;
template
struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
T _data;
};
template
class List
{
typedef ListNode Node;
public:
List()//
{
_head = new Node;
_head->_next = _head->_prev = _head;
}
List(const List& h) //
{
Node* head = h._head;
Node* tmp = head->_next;
_head = new Node;
_head->_next = _head->_prev = _head;
while (tmp != head)
{
PushBack(tmp->_data);
tmp = tmp->_next;
}
}
~List() //
{
Clear();
delete _head;
_head = NULL;
}
void PushBack(const T& x) //
{
Node *tmp = new Node;
tmp->_data = x;
Node* tail = _head->_prev;
tail->_next = tmp;
tmp->_prev = tail;
_head->_prev = tmp;
tmp->_next = _head;
}
void PushFront(const T& x) //
{
Node *tmp = new Node;
tmp->_data = x;
Node* cur = _head->_next;
tmp->_prev = _head;
_head->_next = tmp;
tmp->_next = cur;
cur->_prev = tmp;
}
void PopBack() //
{
Node* cur = _head->_prev;
_head->_prev = cur->_prev;
cur->_prev->_next = _head;
delete[]cur;
cur->_next = cur->_prev = NULL;
}
void PopFront() //
{
Node* cur = _head->_next;
_head->_next = cur->_next;
cur->_next->_prev = _head;
}
void Insert(Node* pos,const T& x) //
{
Node* cur = new Node;
cur->_data = x;
cur->_prev = pos->_prev;
pos->_prev->_next = cur;
pos->_prev = cur;
cur->_next = pos;
}
void Erase(Node* pos) //
{
Node* cur = pos->_next;
pos->_prev->_next = cur->_next;
cur->_next->_prev = pos->_prev;
}
void Clear() //
{
Node* cur = _head->_next;
while(cur != _head)
{
Node* tmp = cur;
cur = cur->_next;
delete tmp;
}
_head->_next = _head;
_head->_prev = _head;
}
Node* Find(const T& x) //
{
Node* cur = _head->_next;
while (cur != _head)
{
if(cur->_data==x)
return cur;
cur = cur->_next;
}
return NULL;
}
size_t Size() //
{
size_t count = 0;
Node* cur = _head->_next;
while (cur != _head)
{
count++;
cur = cur->_next;
}
return count;
}
bool Empty()
{
if (_head->_next = _head->_prev)
return 1;
return 0;
}
void PrintList() //
{
Node* tmp = _head->_next;
while (tmp != _head)
{
std::cout<_data<_next;
}
std::cout<<:endl protected:="" node="" _head=""/>
。