好吧,我有一个抽象的虚拟机(“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)。
答案 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来为数组添加条目。