如何在编译时或代码初始化时自动更新数组中的条目?

时间:2012-12-24 20:48:29

标签: c++ c visual-studio-2012

好吧,我有一个抽象的虚拟机(“PAWN”),它从我的代码运行,脚本可以执行函数,这些函数从C代码注册到脚本,由C ++执行代码。

c ++代码必须以

的形式提供数组
{ "name_i_want_the_function_to_have_in_the_script" , function_in_my_cpp_code }

如果函数不在数组中,则无法执行。 (因为它不存在“)

所以这就把我们带到了这个:

我的功能如下:

//Pawn Functions
#define PWNFUNC(a) static cell AMX_NATIVE_CALL a(AMX *amx, cell *params)

namespace PawnFunc
{
    PWNFUNC(GGV)
    {
        return pGameInterface->FindGameVersion();
    }
};//namespace PawnFunc

并且带有脚本函数信息的数组位于另一个文件中,如下所示:

AMX_NATIVE_INFO custom_Natives[] =
{
    {   "GetGameVersion", PawnFunc::GGV   },
    {   0,0   }
};

现在的问题是:

是否可以自动更新该阵列? (在编译时或编译初始化时间之前)

现在我必须手动添加每个功能。这有时很烦人,更容易出错。

我想改变它,所以我能做到:

//Pawn Functions
#define PWNFUNC(a,b) ...?...

namespace PawnFunc
{
    PWNFUNC(GGV,GetGameVersion)//{ "GetGameVersion", PawnFunc::GGV }, is now added to "custom_Natives" array
    {
        return pGameInterface->FindGameVersion();
    }
};//namespace PawnFunc

这有可能吗?如果是的话,我怎么能实现这个目标呢?

也许可以循环命名空间?

编辑:这是一些伪代码:http://ideone.com/btG2lx

还有一个注释:我可以在运行时执行此操作,但必须在DLLMain完成(我的程序是DLL)。

4 个答案:

答案 0 :(得分:1)

如果您使用#define作为脚本信息的存储空间,则此std::vector将完成此任务。

(请注意,该标准保证您仍然可以从&custom_Natives[0]获得C风格的数组)

std::vector<AMX_NATIVE_INFO> custom_Natives;

#define PWNFUNC(NAME, FUNC) \
 struct IMPL_ ## FUNC { \
   IMPL_ ## FUNC() { \
     AMX_NATIVE_INFO entry = { NAME, PawnFunc::FUNC }; \
     custom_Natives.push_back( entry ); \
   } \
 } INSTANCE_ ## FUNC; \
 static cell AMX_NATIVE_CALL FUNC(AMX *amx, cell *params)

现在这样的代码将定义函数将脚本条目添加到custom_Natives

PWNFUNC("GetGameVersion", GGV)
{
    return pGameInterface->FindGameVersion();
}

答案 1 :(得分:0)

我能想出什么(假设C风格的数组和C-linkage功能):

AMX_NATIVE_INFO custom_natives[] =
{
    { "GetGameVersion", TheGGVFunc },
    { 0, 0 }
};

// here a function call named `GetGameVersion` was encountered,
// so let's look it up using a naive linear search
const char *toBeCalled = "GetGameVersion"; // obtain this somehow
void (*fptr)(void) = NULL;
for (int i = 0; i < sizeof(custom_natives) / sizeof(*custom_natives) - 1; i++) {
    const char *name = custom_natives[i].name;
    if (strcmp(toBeCalled, name) == 0) {
        fptr = custom_natives[i].func;
        break;
    }
}

if (fptr != NULL) {
    fptr();
}

答案 2 :(得分:0)

你可以近似它;我们的想法是使用全局std::vector而不是C数组,并使用全局对象的构造函数来扩展向量。这样,您的数组将在main()开始执行时初始化。因此,不是custom_Natives数组,而是

std::vector<MethodArrayElementType> custom_Natives;

vector(将MethodArrayElementType替换为包含字符串的结构的名称 - &gt;函数指针映射)。您可以使用&custom_Natives[0]将此向量视为普通C数组。

然后,在您定义的每个函数旁边,添加一个Registrar类来注册方法:

PWNFUNC(GGV) {
    // Your implementation goes here...
}

struct GGV_Registrar {
    GGV_Registrar() {
         MethodArrayElementType e = { "GetGameVersion", GGV };
        custom_Natives.push_back( e );
    };
} GGV_Registrar_instance;

在调用GGV_Registrar_instance之前将调用全局main()构造函数的构造函数,它将更新custom_Natives向量。

答案 3 :(得分:0)

我们做这样的事情,但我们不使用数组而是使用链表。所以你的例子将成为

namespace PawnFunc
{
    PWNFUNC(GGV)
    {
        return pGameInterface->FindGameVersion();
    }
    PawnRegister GGVfunc( "GetGameVersion", GGV );
};//namespace PawnFunc

PawnRegister的构造函数将所有对象(如GVVfunc)添加到链接列表中。当您的脚本引擎想要查找函数时,它会遍历列表而不是扫描数组。我想你可以设置PawnRegister来为数组添加条目。