如何通过函数指针调用不同签名的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 引用。

另请参阅:工厂设计模式、访问者设计模式、双重调度