【関数テンプレート】引数や戻り値の型が違っても動く関数の書き方【MQL5】

#関数テンプレートとは
　通常の関数は引数と戻り値にデータ型の指定をします。例えば、引数がdouble型の関数にint型を渡して呼び出そうとしてもコンパイルエラーとなってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/fd598a1a-968d-d866-8d7b-b40bc62c28d0.png)
　関数テンプレートを利用すると引数と戻り値にデータ型の指定をせずに関数を作成することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/f1d75021-204b-14f5-2222-f018dc7392f1.png)


#どんなときに使うの？
　ここでは数値が入った配列を引数にして、その配列内の数値の平均値を戻り値とする関数を例に解説していきます。

　実際に関数を使うときは配列の中身がint型でもdouble型でも数値であれば、なんでもいいわけなので、どんな型でも受け付けてくれるような関数にすること使いやすいものになるのではないでしょうか？

##普通に関数を書くと…

double型の配列の中身の平均値を求める関数を用意して
メイン関数で

- double型の配列で呼び出し
- int型の配列で呼び出し

この2つを試してみます。


```.cpp
// 配列の平均値を計算する
double MathMean(const double &array[])
  {
   int size = ArraySize(array);

   // 平均値を計算
   double mean = 0.0;
   for(int i = 0; i < size; i++)
      mean += array[i];
   mean = mean / size;

   return mean;
  }

void OnStart()
  {
   double arr_d[3] = { 5, 2, 3};
   int    arr_i[3] = { 5, 2, 3};

   Print("double型の配列の平均値 ", MathMean(arr_d));
   Print("int型の配列の平均値    ", MathMean(arr_i));
  }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/25f36b93-9d15-6b93-2099-2ec53e0de5da.png)
int型の配列を引数にするとコンパイルエラーとなってしまいます。

##関数テンプレートを利用すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/9da027e2-6da5-6821-b674-b50080126532.png)
　先ほどと同様にメイン関数で

- double型の配列で呼び出し
- int型の配列で呼び出し

この2つを試してみます。

```.cpp
template<typename T>
T MathMean(const T &array[])
  {
   int size = ArraySize(array);

   // 平均値を計算
   T mean = 0.0; // 型の指定をTとする
   for(int i = 0; i < size; i++)
      mean += array[i];
   mean = mean / size;

   return mean;
  }

void OnStart()
  {
   double arr_d[3] = { 5, 2, 3};
   int    arr_i[3] = { 5, 2, 3};

   Print("double型の配列の平均値 ", MathMean(arr_d));
   Print("int型の配列の平均値    ", MathMean(arr_i));
  }
```
　これでエラーなくコンパイルすることができます(警告は出る)。実際に動作させると↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/c4ada6ff-d8ab-14a4-7d07-a10a727948c2.png)
　int型を引数にしたときは関数内部の処理もint型となるので小数点以下が切り捨てられた状態で返ってきます。

#戻り値か引数どちらか一方のみをテンプレートパラメータにする
　今度はどんな型の数値を引数にしてもdouble型として処理し、戻り値もdouble型にする関数を作ってみます。

```.cpp
template<typename T>
double MathMean(const T &array[]) // 引数のみ型の指定をTとする
  {
   int size = ArraySize(array);

   // 平均値を計算
   double mean = 0.0;
   for(int i = 0; i < size; i++)
      mean += array[i];
   mean = mean / size;

   return mean;
  }

void OnStart()
  {
   double arr_d[3] = { 5, 2, 3};
   int    arr_i[3] = { 5, 2, 3};

   Print("double型の配列の平均値 ", MathMean(arr_d));
   Print("int型の配列の平均値    ", MathMean(arr_i));
  }
```
　こんどはエラーも警告もなくコンパイルすることができます。実際に動作させると↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/ff945ce6-a985-e3a7-4b0c-56e4a786fd52.png)
　このように引数、もしくは戻り値のどちらか片方をテンプレートパラメータとすることができます。
#複数のテンプレートパラメータを作る
　テンプレートパラメータは複数作ることができます。

```.cpp
template<typename T,typename U,typename V>
void func(const T a, const U b, const V c)
  {
   Print(a);
   Print(b);
   Print(c);   
  }

void OnStart()
  {
   int    x = 3;
   double y = 5.1;
   string z = "文字";
   
   func(x,y,z);
  }
```
動作↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/97258546-d442-36d8-bc6a-ccfafb3285e9.png)