头文件
#include <functional>
实现
// 实现一个通用的apdu准备的函数,通过调用p方法来实现协议的wrap和发送
// 方法 p 来将 apdu 打包为[head][apdu][tail]
// 这里我们想让 protocolUse 是一个函数指针
template<typename protocolUse,typename flagType>
void packDlmsHandAndSend(Meter* mtr,CGXDLMSSecureClient& gx,DLMS_COMMAND type,protocolUse p,flagType flag)
{
p(mtr, bufout[0],flag);
}
一个类想调用这个方法
// 类自身的底层包装,发送函数,即 protocolUse
int IEC46::sendToMeter(void)
{
return 0;
}
int IEC46::sendToMeter(Meter *meter, CGXByteBuffer &subGxData, IEC46::comTypeEnum flag)
{
return sendToMeter(meter, Buffer(subGxData.GetData(), subGxData.GetSize()), flag);
}
// 这个是函数的类型,注意这里不能使用 mm来取代Fun
// bind 的返回是 function 不是简单的函数指针
// typedef int (*mm)(Meter *meter, CGXByteBuffer &subGxData, IEC46::comTypeEnum flag);
typedef std::function<int (Meter *meter, CGXByteBuffer &subGxData, IEC46::comTypeEnum flag)> Fun;
using mysend = int(IEC46::*)(Meter *meter, CGXByteBuffer &subGxData, IEC46::comTypeEnum flag);
// 1. 绑定一个函数,这里可以直接使用auto bindFunc2
// 这里的类型声明 mysend 不可省略,因为有重载的同名成员函数,如果没有同名的,可以省略
Fun bindFunc2 = std::bind((mysend)&IEC46::sendToMeter,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
// 2. 调用形式可以省略掉 <Fun,IEC46::comTypeEnum>
packDlmsHandAndSend<Fun,IEC46::comTypeEnum>(mtr,gxClient,DLMS_COMMAND_DISCONNECT_REQUEST,bindFunc2,comTask);
//3. 精简的形式可以如下:
using mysend = int(IEC46::*)(Meter *meter, CGXByteBuffer &subGxData, IEC46::comTypeEnum flag);
auto bindFunc2 = std::bind((mysend)&IEC46::sendToMeter,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
packDlmsHandAndSend(mtr,gxClient,DLMS_COMMAND_DISCONNECT_REQUEST,bindFunc2,comTask);
简单一点的形式
其实在这里,我们可以直接传递类为模版到packDlmsHandAndSend
,然后调用p.sendToMeter(xxx)
iec46下的成员函数,调用
makeApdu(type,sendByIec46) 发送数据
更理想的应该是
iec46类下面有个发送函数,调用 makeApdu ,最终发送数据