如何通过函数指针调用不同签名的C++函数
How to call C++ functions with different signatures through function pointer
我有一个 C++ 应用程序,其中 main() 实例化一个对象 MyApp,然后将该对象传递给 ReadConfig 函数。
ReadConfig 打开一个基于文本的文件,对其进行解析,然后调用适当的 MyApp 方法对其进行配置。
class MyApp
{
private:
public:
void SetRate(uint16_t);
void EnableLogging(bool);
void SetAddress(uint32_t);
};
我正在努力使 ReadConfig 的维护变得容易,这样当新的 public 方法被添加到 MyApp 时,它可以像更新 table 一样简单。我想出了以下解决方案,但我不喜欢它。由于必须确保我将 0 放在正确的位置,因此很难维护。
以下是我能够解决的问题的示例。任何使这更好的建议将不胜感激。请注意,我在嵌入式系统中工作,因此我们使用的 C++ 编译器不支持 C++14 并且没有提升。我想避免使用任何 STL 库,以便自己了解执行此操作的机制。
这是我的资料:
enum ARGTYPE {TBOOL, TUINT16, TUINT32};
template<typename TOBJ, typename TARG>
struct TSetting
{
void (TOBJ::*FSet)(TARG);
};
template<typename obj>
struct SETTINGFN
{
const char *setting_name;
ARGTYPE Targ;
TSetting<obj,bool> HBool;
TSetting<obj,uint16_t> HUint16;
TSetting<obj,uint32_t> HUint32;
};
SETTINGFN<MyApp> MyAppSettings[] =
{
"logging" ,TBOOL, &MyApp::EnableLogging, 0,0,0
,"maxrate" ,TUINT16, 0,0,0,&MyApp::SetRate
,"address" ,TUINT32, 0, &MyApp::SetAddress, 0,0
};
unsigned int MyAppSettings_Count = sizeof(MyAppSettings) / sizeof(SETTINGFN<MyApp>);
然后当我读取配置文件并解析它时,我调用一个函数来处理通过函数指针调用实际 MyApp 函数。该函数如下:
bool AppSetting(MyApp &E, TObjnode &node)
{
bool rval = false;
for(unsigned int i=0; i<MyAppSettings_Count && !rval; i++)
{
if(node.GetName() == MyAppSettings[i].setting_name)
{
rval = true;
switch(MyAppSettings[i].Targ)
{
case TBOOL:
(E.*MyAppSettings[i].HBool.FSet)(node.GetValue().AsBool());
break;
case TUINT16:
(E.*MyAppSettings[i].HUint16.FSet)(node.GetValue().Value());
break;
case TUINT32:
(E.*MyAppSettings[i].HUint32.FSet)(node.GetValue().Value());
break;
}
}
}
return(rval);
}
您设计中的棘手问题是不同的参数类型。
如果把参数抽象成一个结构体,那么函数就可以简化为一个固定的签名。
通过使用基本结构,签名更通用:
struct Arguments_Base
{
};
void SetRate(Arguments_Base& ab);
void EnableLogging(Arguments_Base& ab);
void SetAddress(Arguments_Base& ab);
通过统一签名,函数指针或函数对象可以在tables或映射中使用,使得搜索更轻松。搜索引擎应该能够通用并依赖于数据的大小,以便只需要更改数据(例如 table),而不是搜索引擎。
每种类型的参数集都应派生自 Arguments_Base
class。然后该函数可以 dynamic_cast
基数 class 引用。
另请参阅:工厂设计模式、访问者设计模式、双重调度
我有一个 C++ 应用程序,其中 main() 实例化一个对象 MyApp,然后将该对象传递给 ReadConfig 函数。
ReadConfig 打开一个基于文本的文件,对其进行解析,然后调用适当的 MyApp 方法对其进行配置。
class MyApp
{
private:
public:
void SetRate(uint16_t);
void EnableLogging(bool);
void SetAddress(uint32_t);
};
我正在努力使 ReadConfig 的维护变得容易,这样当新的 public 方法被添加到 MyApp 时,它可以像更新 table 一样简单。我想出了以下解决方案,但我不喜欢它。由于必须确保我将 0 放在正确的位置,因此很难维护。
以下是我能够解决的问题的示例。任何使这更好的建议将不胜感激。请注意,我在嵌入式系统中工作,因此我们使用的 C++ 编译器不支持 C++14 并且没有提升。我想避免使用任何 STL 库,以便自己了解执行此操作的机制。
这是我的资料:
enum ARGTYPE {TBOOL, TUINT16, TUINT32};
template<typename TOBJ, typename TARG>
struct TSetting
{
void (TOBJ::*FSet)(TARG);
};
template<typename obj>
struct SETTINGFN
{
const char *setting_name;
ARGTYPE Targ;
TSetting<obj,bool> HBool;
TSetting<obj,uint16_t> HUint16;
TSetting<obj,uint32_t> HUint32;
};
SETTINGFN<MyApp> MyAppSettings[] =
{
"logging" ,TBOOL, &MyApp::EnableLogging, 0,0,0
,"maxrate" ,TUINT16, 0,0,0,&MyApp::SetRate
,"address" ,TUINT32, 0, &MyApp::SetAddress, 0,0
};
unsigned int MyAppSettings_Count = sizeof(MyAppSettings) / sizeof(SETTINGFN<MyApp>);
然后当我读取配置文件并解析它时,我调用一个函数来处理通过函数指针调用实际 MyApp 函数。该函数如下:
bool AppSetting(MyApp &E, TObjnode &node)
{
bool rval = false;
for(unsigned int i=0; i<MyAppSettings_Count && !rval; i++)
{
if(node.GetName() == MyAppSettings[i].setting_name)
{
rval = true;
switch(MyAppSettings[i].Targ)
{
case TBOOL:
(E.*MyAppSettings[i].HBool.FSet)(node.GetValue().AsBool());
break;
case TUINT16:
(E.*MyAppSettings[i].HUint16.FSet)(node.GetValue().Value());
break;
case TUINT32:
(E.*MyAppSettings[i].HUint32.FSet)(node.GetValue().Value());
break;
}
}
}
return(rval);
}
您设计中的棘手问题是不同的参数类型。
如果把参数抽象成一个结构体,那么函数就可以简化为一个固定的签名。
通过使用基本结构,签名更通用:
struct Arguments_Base
{
};
void SetRate(Arguments_Base& ab);
void EnableLogging(Arguments_Base& ab);
void SetAddress(Arguments_Base& ab);
通过统一签名,函数指针或函数对象可以在tables或映射中使用,使得搜索更轻松。搜索引擎应该能够通用并依赖于数据的大小,以便只需要更改数据(例如 table),而不是搜索引擎。
每种类型的参数集都应派生自 Arguments_Base
class。然后该函数可以 dynamic_cast
基数 class 引用。
另请参阅:工厂设计模式、访问者设计模式、双重调度