函数模板
重载函数通常被用于执行各种数据类型的类似的操作。ArraySize() 是MQL5中这种函数的一个简单例子。它返回任何类型的数组大小。实际上,是由应用程序开发人员重载这个系统函数并且隐藏重载的整个实施:
int ArraySize(
void& array[]
);
|
它意味着MQL5语言编译器每次调用这个函数都要插入必要的实施。例如,那就是整型数组如何完成的方法:
int ArraySize(
int& array[]
);
|
ArraySize() 函数可以按照以下方式展示 MqlRates 类型数组,以便以历史数据格式处理报价:
int ArraySize(
MqlRates& array[]
);
|
因此,使用相同函数处理不同类型非常地方便。然而,应该先执行所有初步的工作 - 应该为正确处理的所有数据类型重载 必要的函数。
但,这里有更方便的解决方案。如果,每个数据类型都应执行类似的操作,那么就可以使用函数模板。在这种情况下,程序员只需要编写一个函数模板的描述。当以这种方式描述模板时,我们应该只指定一个正式参数来替代函数处理的定义的数据类型。编译器将会自动生成多种函数,以便适当处理基于用于调用函数的参数类型的每种类型。
函数模板定义以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 关键字进行声明。
模板函数重载
重载模板函数有时可能是必需的。例如,我们有一个使用类型转换在第一个参数编写第二参数值的模板函数。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)
|
另见
重载