14
15 for (int i=0; i<a.getSize(); i++) { 16 a[i] = i+10;
17 b[i] = i*i;
18 }
19 showContentsOf("a", a);
20 showContentsOf("b", b);
21
22 a = b;
23 cout << "a = b;" << endl;
24 cout << "==> ";
25 showContentsOf("a", a);
26 } 27
28 void showContentsOf(string arrayName, SafeArray<int> a) 29 {
30 cout << arrayName << ".size=" << a.getSize() << ", "
31 << arrayName << "=(";
32 for (SafeArray<int>::iterator p=a.begin(); p!=a.end(); ++p) 33 cout << right << setw(4) << *p;
34 cout << ")" << endl;
35 }
[motoki@x205a]$ g++ useSafeArrayInt.cpp [motoki@x205a]$ ./a.out
a.size=10, a=( 10 11 12 13 14 15 16 17 18 19) b.size=10, b=( 0 1 4 9 16 25 36 49 64 81) a = b;
==> a.size=10, a=( 0 1 4 9 16 25 36 49 64 81) [motoki@x205a]$
ここで、
3 利用例のプログラム32∼33行目 では、全ての配列要素を出力する繰り返し処理が データ集合 {a[0], a[1], ..., a[a.size-1]} を保持する方法に依存しない形で記 述されている。この32∼33行目に現れる変数 p の様に、処理する要素を次々に指 すiterator型の変数を反復子(iterator,イテレータ) と呼ぶ。
6.2 型パラメータ付きの関数定義
{Pohl(1999)7.2節} 通常の関数内に現れるデータ型の部分をパラメータ化することもできる。型パラメータ 付きの関数をテンプレート関数もしくは関数テンプレートと呼ぶ。
例 6.3 (配列全体をコピーする型パラメータ付き関数) 指定された型パラメータTYPE1,
TYPE2に対して「TYPE2型配列をTYPE1型配列に要素単位でコピーするテンプレート関数
178 6. パラメータ付きのクラス定義、総称的プログラミング、STL
copy()」、および指定された型パラメータTYPEに対して「TYPE型配列の要素列を出力す
るテンプレート関数print()」を定義し使用した例を次に示す。
[motoki@x205a]$ cat -n useTemplateCopy.cpp
1 // 型パラメータ付きの関数 copy() の定義・利用例 2
3 #include <iostream>
4 #include <iomanip>
5 #include <string>
6 using namespace std;
7
8 template<typename TYPE1, typename TYPE2>
9 void copy(TYPE1 x[], TYPE2 y[], int size);
10
11 template<typename TYPE>
12 void print(string arrayName, TYPE x[], int size);
13
14 int main() 15 {
16 double a[5] = {1.1, 2.2, 3.3, 4.4, 5.5}, b[5];
17 int m[5];
18
19 print("a", a, 5);
20 ::copy(b, a, 5);
21 print("b", b, 5);
22
23 ::copy(m, a, 5);
24 print("m", m, 5);
25 } 26
27 template<typename TYPE1, typename TYPE2>
28 void copy(TYPE1 x[], TYPE2 y[], int size) 29 {
30 for (int i=0; i<size; ++i) 31 x[i] = y[i];
32 } 33
34 template<typename TYPE>
35 void print(string arrayName, TYPE x[], int size) 36 {
37 cout << arrayName << "[" << size << "] = {" << scientific << fixed;
38 for (int i=0; i<size-1; ++i) 39 cout << x[i] << ", ";
40 cout << x[size-1] << "}" << endl;
6.2. 型パラメータ付きの関数定義 179
41 }
[motoki@x205a]$ g++ useTemplateCopy.cpp [motoki@x205a]$ ./a.out
a[5] = {1.100000, 2.200000, 3.300000, 4.400000, 5.500000}
b[5] = {1.100000, 2.200000, 3.300000, 4.400000, 5.500000}
m[5] = {1, 2, 3, 4, 5}
[motoki@x205a]$
ここで、
• プログラム20行目,23行目 でスコープ解決演算子:: を用いているのは、標準ライブ ラリstd内で定義されたcopy()関数を適用候補から除外するためである。
例 6.4 (2つの変数の中身を交換する型パラメータ付き関数) 例2.5で定義した関数void swap(int&, int&) の引数の型の部分をパラメータ化し、指定された型パラメータTYPE に対して「TYPE型の2つの変数の中身を交換する(テンプレート)関数swap()」を定義し 使用した例を次に示す。
[motoki@x205a]$ cat -n useTemplateSwap.cpp
1 // 型パラメータ付きの関数 swap() の定義・利用例 2
3 #include <iostream>
4 #include <cstring>
5 using namespace std;
6
7 template<typename TYPE>
8 void swap(TYPE& x, TYPE& y);
9
10 void swap(char* x, char* y);
11
12 int main() 13 {
14 int i=1, j=22;
15 double a=33.3, b=444.4;
16 char str1[]="abcd", str2[]="1234";
17
18 ::swap(i, j);
19 cout << "i=" << i << ", j=" << j << endl;
20
21 ::swap(a, b);
22 cout << "a=" << a << ", b=" << b << endl;
23
24 ::swap(str1, str2);
25 cout << "str1=" << str1 << ", str2=" << str2 << endl;
26 }
180 6. パラメータ付きのクラス定義、総称的プログラミング、STL
27
28 template<typename TYPE>
29 void swap(TYPE& x, TYPE& y) 30 {
31 TYPE temp;
32
33 temp = x;
34 x = y;
35 y = temp;
36 } 37
38 void swap(char* x, char* y) 39 {
40 int maxLength = max(strlen(x), strlen(y));
41 char* temp = new char[maxLength+1];
42
43 strcpy(temp, x);
44 strcpy(x, y);
45 strcpy(y, temp);
46 delete[] temp;
47 }
[motoki@x205a]$ g++ useTemplateSwap.cpp [motoki@x205a]$ ./a.out
i=22, j=1
a=444.4, b=33.3 str1=1234, str2=abcd [motoki@x205a]$
ここで、
• プログラム18行目,21行目,24行目 でスコープ解決演算子 :: を用いているのは、標 準ライブラリstd内で定義されたswap()関数を適用候補から除外するためである。
• プログラム40行目 に現れるmax()は、標準ライブラリstd内で定義されたmax()関 数を表す。
• プログラム24行目 の関数呼び出し ::swap(str1, str2); に対しては、28∼36行目 で定義されたテンプレート関数も、38∼47行目で定義された非テンプレート関数も適 用可能である。こういう場合は、非テンプレート関数の方が優先的に適用される。一 般に、適用可能な関数が複数あった時は、次の順に優先的に選ばれる。
1 自明の型変換を行うことによりシグネチャが合致する非テンプレート関数 2 適切に型パラメータを設定することによりシグネチャが合致するテンプレート
関数
3 非テンプレート関数上での通常の選択手順による関数(−→2.11節を参照)