动态调用C ++(成员)函数

时间:2013-10-08 09:29:31

标签: c++ reflection bind

假设我有一些反射元数据,其中包含以下信息:

enum class type { t_int, t_double, t_str /* etc... */ };

struct meta_data
{
    void* function;
    void* instance;
    std::vector<type> param_types;
};

std::map<std::string, meta_data> ftable;

我想在这个地图中调用函数,给定函数名称和参数都为 strings 。我的问题不是转换参数(例如使用boost::lexical_cast),而是转换为正确类型的函数指针并调用函数。如果我允许8种类型和最多8种参数,那我的代码中已经有很多分支。我想避免的(伪代码):

    switch (md.param_types.size())
    {
    case 0:
         cast function pointer, call it
         break;
    case 1:
         switch (md.param_types[0])
         {
         case t_int:
                    int param = boost::lexical_cast(param_strings[0]);
                  cast function pointer, call with param
         case ...
         }
         break;
    case 2:
         switch (md.param_types[0]) {
         case t_int:
             int param = boost::lexical_cast(param_strings[0]);
             switch (md.param_types[1]) {...} // second param type..
         }
         break;
    case n...
    }

随着参数数量和可能的类型,这会很快爆发。我正在寻找一些解决方案(伪代码):

for (auto& p : paramter_strings)
{
    convert p to a variable of matching type (type id comes from meta_data).
    store value
}

call function with stored values

即。没有函数调用的分支。如何使用最少量的样板代码(可能支持任意数量的参数)来完成此操作?您可以将此视为创建自定义脚本语言的绑定。

1 个答案:

答案 0 :(得分:0)

我提出了一种方法。

假设你有一个unsigned int V的向量,你就知道了 向量的每个元素都是非负数 它小于N(或者说,例如20)。 以下是您要将矢量V更改为a的内容 正整数:

n = sequence_to_code(V,N); // or n = encode(V,20U);

这是代码。

long sequence_to_long(const std::vector<unsigned int> & L,
                      unsigned long n) {
  long result = 0L;
  std::vector<unsigned int>::const_iterator w=L.begin(),e=L.end();
  if(w!=e) {
    result += (*w)+1;
    unsigned long the_pow = n;
    unsigned int i = 1U;
    ++w;
    while(w!=e) {
      result += (*w+1)*(the_pow);
      ++w;++i;the_pow *= n;
    }
  }
  return result;
}

实际上,我可能应该返回“unsigned long”。

此外,您可以将同一例程与创建的程序一起使用 一个文本文件。该文本文件将包含C ++代码。假设你创建了 “the_defines.hpp”。我将举例说明......

例如,假设我们有t_int = 0; t_double = 1,d_str = 2 而且只有三种类型。 然后“the_define.hpp”可以是文件:

#define TYPE_EMPTY 0U
#define TYPE_INT   1U
#define TYPE_DOUBLE 2U
#define TYPE_STR    3U
#define TYPE_INT_INT 4U
#define TYPE_DOUBLE_INT 5U

然后可以在下面使用此代码 方式:

std::vector<unsigned int> L;
// add entries to L
long n = sequence_to_long(L,3UL);
switch(n) {
  case TYPE_INT:
    std::cout << "an integer\n";
    break;
  case TYPE_INT_DOUBLE:
    std::cout << "two args; first is an int; second is a double\n:
    break;
}

当然,您可以创建一个包含非常代码的文本文件 长枚举(如果你想避免#define)。例如,

enum class extended_type { 
  type_int,
  type_double,
  type_str,
  type_int_int,
  type double_int,

等等。

您还可以编写一个创建(一个或多个)文本文件的程序。 这些文本文件也可以通过C ++代码实现。例如,您创建的文件 可能是:

swtich(n) {
  case empty:
    FILLIN
    break; 
  case t_int:
    FILLIN
    break;

等等,直到

  case t_str_str:
    FILLIN;
    break;
 }

我还建议使用内联函数或常规函数进行投射 功能。例如,

inline int inside_int(foo f) {
  const bar & b = * reinterpret_cast<const bar *>(f.pointer());
  return b.d_x;
}

我建议这是因为DRY(不要重复自己)和存在 能够搜索该函数的所有实例。

我知道这些程序不处理错误(溢出, 零指针等。)

标记