함수 템플릿

오버로드 함수는 일반적으로 다양한 데이터 유형에 대해 유사한 작업을 수행하는 데 사용됩니다. ArraySize()는 MQL5에서 이러한 함수의 간단한 예입니다. 이는 모든 유형의 배열 크기를 반환합니다. 실제로 이 시스템 기능은 오버로드 상태이며 이러한 오버로드의 전체 구현은 MQL5 애플리케이션 개발자에게 숨겨져 있습니다:

int  ArraySize(
   void&  array[]      // 체크된 배열
   );

즉, MQL5 언어 컴파일러는 이 함수의 각 호출에 필요한 구현을 삽입합니다. 예를 들어, 정수형 배열에 대해 다음과 같이 수행할 수 있습니다:

int  ArraySize(
   int&  array[]      // int 형식 요소가 있는 배열
   );

ArraySize() 함수는 과거 데이터 형식의 따옴표로 작업하기 위해 MqlRates 유형 배열에 대해 다음과 같은 방법으로 표시할 수 있습니다:

int  ArraySize(
   MqlRates&  array[] // MqlRates 유형 값으로 채워진 배열
   );

따라서 동일한 기능을 사용하여 다른 유형의 작업을 수행하는 것이 매우 편리합니다. 그러나 모든 예비 작업을 수행해야 합니다. 필요한 기능은 올바르게 작동해야 하는 모든 데이터 유형에 대해 오버로드되어야 합니다.

편리한 해결책이 있습니다. 각 데이터 유형에 대해 유사한 작업을 실행해야 하는 경우 함수 템플릿을 사용할 수 있습니다. 이 경우 프로그래머는 하나의 기능 템플릿 설명만 작성하면 됩니다. 그러한 방법으로 템플릿을 설명하는, 우리는 어떤 일정한 데이터 기능과 협력해야 합니다. 대신에 단지 일부 형식 매개 변수가 지정되어야 합니다. 컴파일러는 함수를 호출할 때 사용되는 인수 유형에 따라 각 유형의 적절한 처리를 위한 다양한 함수를 자동으로 생성합니다.

함수 템플릿 정의는 template 키워드 다음에 대괄호 안의 형식 매개 변수 목록으로 시작합니다. 각 형식 파라미터 앞에는 typename 키워드가 표시됩니다. 형식 매개 변수 유형은 기본 제공 유형 또는 사용자 정의 유형입니다. 다음과 같이 사용됩니다:

  • 함수 인수 유형을 지정;
  • 함수의 반환 값 유형을 지정,
  • 함수 정의 내에서 변수를 선언

 

템플릿 매개 변수 수는 8개를 초과할 수 없습니다. 템플릿 정의의 각 형식 매개 변수는 함수 매개 변수 목록에 한 번 이상 나타나야 합니다. 형식 매개 변수의 각 이름은 고유해야 합니다.

다음은 모든 숫자 유형(정수 및 실수)의 배열에서 가장 높은 값을 검색하는 함수 템플릿의 예입니다:

template<typename T>
T ArrayMax(T &arr[])
  {
   uint size=ArraySize(arr);
   if(size==0) return(0);          
   
   T max=arr[0];
   for(uint n=1;n<size;n++)
      if(max<arr[n]) max=arr[n];
//---
   return(max);
  }

이 템플릿은 전달된 배열에서 가장 높은 값을 찾고 그 결과로 이 값을 반환하는 함수를 정의합니다. MQL5에 내장된 ArrayMaximum() 함수는 값 자체를 찾는 데 사용할 수 있는 가장 높은 값 인덱스만 반환합니다. 예:

//--- 배열 생성
   double array[];
   int size=50;
   ArrayResize(array,size);
//---  랜덤 값으로 채움
   for(int i=0;i<size;i++)
     {
      array[i]=MathRand();
    }
 
//--- 배열에서 가장 높은 값의 위치 찾기
   int max_position=ArrayMaximum(array);
//--- 이제 어레이에서 가장 높은 값 자체를 가져옵니다
   double max=array[max_position];
//--- 찾은 값 표시
   Print("Max value = ",max);

따라서 어레이에서 가장 높은 값을 얻기 위해 두 단계를 수행했습니다. ArrayMax() 함수 템플릿을 사용하면 적절한 유형의 배열을 이 함수에 전달하는 것만으로도 필요한 유형의 결과를 얻을 수 있습니다. 마지막 두 줄 대신을 뜻합니다

//--- 배열에서 가장 높은 값의 위치 찾기
   int max_position=ArrayMaximum(array);
//--- 이제 어레이에서 가장 높은 값 자체를 가져옵니다
   double max=array[max_position];

이제 반환된 결과의 유형이 함수에 전달된 배열과 동일한 한 줄만 사용할 수 있습니다:

//--- 가장 높은 값을 발견
   double max=ArrayMax(array);

이 경우 ArrayMax() 함수에 의해 반환되는 결과 유형이 배열 유형과 자동으로 일치합니다.

 

typename 키워드를 사용하여 인수 유형을 문자열로 가져와 다양한 데이터 유형으로 작업하는 범용 메서드를 만들 수 있습니다. 데이터 형식을 문자열로 반환하는 함수의 구체적인 예를 살펴보겠습니다:

#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- 
   CTrade trade;   
   double d_value=M_PI;
   int i_value=INT_MAX;
   Print("d_value: type=",GetTypeName(d_value), ",   value=", d_value);
   Print("i_value: type=",GetTypeName(i_value), ",   value=", i_value);
   Print("trade: type=",GetTypeName(trade));
//--- 
  }
//+------------------------------------------------------------------+
//| 유형이 라인으로 반환됩니다                                          |
//+------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
  {
//--- 유형을 행으로 반환
   return(typename(T));
//---
  }

 

함수 템플릿은 다음과 같은 클래스 메서드에도 사용할 수 있습니다:

class CFile
  {
   ...
public:
   ...
   template<typename T>
   uint WriteStruct(T &data);
  };
 
template<typename T>
uint CFile::WriteStruct(T &data)
  {
   ...
   return(FileWriteStruct(m_handle,data));
  }

함수 테플릿은 export, virtual#import 키워드로 선언하면 안 됩니다.

템플릿 함수 오버로드

때로는 템플릿 함수 오버로드가 필요할 수 있습니다. 예를 들어, typecasting을 사용하여 두 번째 파라미터의 값을 첫 번째 파라미터에 쓰는 템플릿 함수가 있습니다. MQL5에서는 string - bool 타입캐스팅을 사용할 수 없습니다. 템플릿 함수의 오버로드를 생성해 보겠습니다. 예:

//+------------------------------------------------------------------+
//| 템플릿 함수                                                        |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
  {
   var1=(T1)var2;
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| bool+string용 특별 오버로드                                        |
//+------------------------------------------------------------------+
string Assign(bool &var1,string var2)
  {
   var1=(StringCompare(var2,"true",false) || StringToInteger(var2)!=0);
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| 스크립트 프로그램 시작 함수                                          |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i;
   bool b;
   Print(Assign(i,"test"));
   Print(Assign(b,"test"));
  }

코드 실행 결과 int+string 페어에 Assign() 템플릿 함수가 사용되었고 오버로드된 버전은 두 번째 호출 중에 이미 bool+string 페어에 사용되었음을 알 수 있습니다.

string Assign<int,string>(int&,string)
string Assign(bool&,string)

더 보기

오버로드