Как автоматически обновлять записи в массиве до / во время компиляции или во время инициализации кода?

Ну, у меня есть абстрактная виртуальная машина (пешка«), который выполняется из моего кода, и сценарии могут выполнять функции, эти функции регистрируются в сценарии из кода 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

Решение

это #define будет делать работу, если вы используете std::vector в качестве хранилища для вашей информации скрипта.

(Обратите внимание, что стандарт гарантирует, что вы все равно получите массив в стиле C от &custom_Natives[0])

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

Другие решения

Что я мог бы придумать (предполагая массивы в стиле 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();
}
0

Вы можете приблизить это; идея заключается в использовании глобального std::vector вместо массива C, и использовать конструкторы глобальных объектов для расширения вектора. Таким образом, ваш массив будет инициализирован ко времени main() начинает выполнять. Так что вместо custom_Natives массив у вас будет

std::vector<MethodArrayElementType> custom_Natives;

вектор (заменить MethodArrayElementType с именем структуры, которая содержит строку -> отображение указателя на функцию). Вы можете рассматривать этот вектор как обычный массив C, используя &custom_Natives[0],

Затем, рядом с каждой определяемой вами функцией, вы добавляете немного 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 вектор.

0

Мы делаем что-то вроде этого, но вместо использования массива мы используем связанный список. Таким образом, ваш пример станет

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

Конструктор для PawnRegister добавляет все объекты (например, GVVfunc) в связанный список. Когда ваш скрипт-движок хочет найти функцию, он просматривает список, а не сканирует массив. Я полагаю, вы могли бы настроить PawnRegister, чтобы вместо этого добавлять записи в массив.

0
По вопросам рекламы [email protected]