函数模板

重载函数通常被用于执行各种数据类型的类似的操作。ArraySize() 是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));
  }

函数模板不能使用 exportvirtual#import 关键字进行声明。

模板函数重载

重载模板函数有时可能是必需的。例如,我们有一个使用类型转换在第一个参数编写第二参数值的模板函数。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"));
  }

作为代码执行结果,我们可以看到Assign()模板函数已经用于int+string组,而第二次调用时重载版本已经用于bool+string组。

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

另见

重载