Level 3:関数 3.7 関数テンプレート

※資料は自著より引用


■3.7 関数テンプレート

●テンプレートテクニック

 次のソースコードで定義されている引数付きマクロ mySortTemplate( T ) は,T型要素の配列を
整列できる関数 mySort( ) の定義を展開するように作成されている(9〜28行目)。

 この引数付きマクロ mySortTemplate( T ) は, あらかじめ特定の要素型の配列を第1引数を受け
取る関数 mySort( ) のオーバロードバージョンの定義をマクロ展開しておくことである。
 ・ 30行目では, mySortTemplate( int ) として,第1引数に int型配列を受け取る
     関数 void mySort( int a[ ], size_t element_num, ::sortFlag flag ); の定義をマクロ展開している。
 ・ 31行目では, mySortTemplate( double ) として,第1引数に double型配列を受け取る
     関数 void mySort( double a[ ], size_t element_num, ::sortFlag flag ); の定義をマクロ展開している。

 そうして,その関数の必要なオーバロードバージョンの定義をマクロ展開しておき,それを呼び出して
いる(45,46,53,54行目)。

 ・マクロ定義による関数定義の一元化 sort4.cpp



●マクロ展開によるテンプレートテクニックの利点と欠点



●関数テンプレート






・関数テンプレートを利用した例 sort5.cpp




●関数テンプレートの仕組み

ソースコードはこちら。 クリックして画像が切り替えられます。


授業内練習問題:※リファレンスとテンプレートを個別に使った課題はこちら
 上図で例に挙げた2つの引数の値を交換するテンプレート関数 mySwap( ) を,ポインタで引数を受け取る形ではなく,
リファレンスで引数を受け取る様に改良せよ。mySwap1.cpp

#include <iostream>

using namespace std;

template< class T > void mySwap( /* ここを完成させよ */  ) {
  T temp = a;
  a = b; b = temp;
}



int main( void ) {

  int x = 10, y = 20;

  mySwap( x, y );

  cout << "x is " << x << endl << "y is " << y << endl;

  double dx = 100.0, dy = 200.0;

  mySwap( dx, dy );

  cout << "dx is " << dx << endl << "dy is " << dy << endl;


  char c; cin >> c; // 1文字タイプしてエンターキー

  return 0;
}

●関数テンプレートの注意点

注意点1:複数の異なるテンプレート仮引数を使用できる。
以下は,二つの実引数のデータサイズを比較して第1実引数のサイズの方が大きいときは1を返し,
そうでない場合は0を返す関数 greater( ) の定義例。テンプレート関数の定義部分で,
< class T1, class T2 > というように,2つのテンプレート仮引数T1T2が宣言されている。

#include <iostream>
#include <cstdlib>

using namespace std;

// 第1実引数のバイトサイズ > 第2実引数のバイトサイズ の場合 1 を返し,
// そうでないなら 0 を返す関数 greater( )。
template< class T1, class T2  >
bool greater( const T1 & a, const T2 & b ) {
  return sizeof( a ) > sizeof( b );
}

int main( void ) {

  int i; short s; double d;

  cout << greater( i, d ) << endl; // 0 と表示。bool greater( const int & a, const double & b ); の定義が自動生成されて使われる。
  cout << greater( i, s ) << endl; // 1 と表示。bool greater( const int & a, const short  & b ); の定義が自動生成されて使われる。

  char c; cin >> c; // 1文字タイプしてエンターキー

  return 0;
}
注意点2:テンプレート 仮引数は返値型にも使用できる(ただし,関数仮引数にテンプレート仮引数を組み込んでおくこと)。
以下は,配列とその要素数を渡すと,配列の要素の中で一番大きい要素の値を返す関数 maxElement( ) の定義である。
返値型がテンプレート仮引数Tになっている。
#include <iostream>

using namespace std;

template< class T >
T maxElement( const T a[ ], size_t num ) {
  T max = a[ 0 ];
  for( size_t i = 1; i < num; i++ ) {
    if( a[ i ] > max ) max = a[ i ];
  }
  return max;
}

int main( void ) {

  int    ia[ ] = { -10, 2, 4, 51,   -100, 17   };
  double da[ ] = { -123.0, 2.0, 4.0, 27.0, 7.0 };

  cout << maxElement( ia, 6 ) << endl; // 51 と表示。 int    maxElement( int    a[ ], size_t num ); の定義が自動生成されて使われる。
  cout << maxElement( da, 5 ) << endl; // 27 と表示。 double maxElement( double a[ ], size_t num ); の定義が自動生成されて使われる。

  char c; cin >> c; // 1文字タイプしてエンターキー

  return 0;
}




● 関数テンプレートを記述する場所