Использование var_arg для передачи параметров для вызовов функций

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

Теперь очевидно, что они не могут быть отображены напрямую, так как один интерфейс требует компиляции C ++, а искажение имени могло бы испортить другой, поэтому я в первую очередь использую набор адаптеров.

Поскольку количество аргументов варьируется, я искал функции с переменными числами и нашел эту идею довольно полезной, однако я работаю только с POD и должен иметь дело со структурами, перечислениями и множеством различных аргументов в вызове, которые, возможно, придется вернуть назад. в структуру, прежде чем передать его целевой функции.

Каждый пример, на который я наткнулся, был намного проще и включал в основном арифметические операции, такие как суммирование, поиск наибольшего числа или печать. Главным образом сделано с циклами for в var_list.

Может быть, я застрял на идее, и она не будет работать вообще, но мне просто любопытно …

Скажем, я хотел назначить аргументы из списка параметрам моей целевой функции (порядок передаваемых аргументов правильный), что было бы хорошим способом?

BOOL Some_Function(
/* in  */ CallerId *pObjectId,
/* in  */ someDataType argument1 )
{
BOOL ret = Adapter_Call(pFunction, pObjectId, argument1);
return ret;
}

и поэтому, как только я сделал это к нужному адаптеру, я хочу сделать

BOOL Adapter_Call(*pFunction, *pObjectId, argument1, ...)
{
va_list args;
va_start(args, argument1);

/*go over list and do `var_list[i] = pFunctionArgList[i]` which is
of whatever type so I can use it as input for my function */

va_end(args);
pObjectId.pFunction(arg1,...,argn);
}

Могу ли я получить доступ к входным параметрам функции для выполнения подобных назначений?
Кто-нибудь делал что-то подобное раньше? Есть ли концептуальная ошибка в моем мышлении?

Все, что я нашел в сети, было это, http://www.drdobbs.com/cpp/extracting-function-parameter-and-return/240000586but из-за использования шаблонов я не уверен, не создаст ли это еще одну проблему, и, в конце концов, реализовать адаптер для каждой функции может быть проще.

SO поиск только вернул это: Динамические вызовы функций во время выполнения (va_list)

1

Решение

Во-первых, вы должны прислушаться к советам Керрека о extern "C", Это механизм C ++ для предоставления связи с идентификатором C, означающий, что имя не будет искажено компилятором C ++.

Иногда, и адаптер все еще должен быть написан для интерфейса C ++, потому что он манипулирует объектами, которые не отображаются в C POD. Таким образом, адаптер предоставляет интерфейсу C тип POD или непрозрачный указатель для манипуляции, но реализация этого интерфейса преобразует его в объект или ссылку C ++ и затем вызывает интерфейс C ++. Например, предположим, что вы хотите предоставить интерфейс C для C ++ std::map<int, void *>, у вас будет общий заголовочный файл на C и C ++, который будет содержать:

#ifdef __cplusplus
extern "C" {
#endif
struct c_map_int_ptr;
// ...
// return -1 on failure, otherwise 0, and *data is populated with result
int c_map_int_ptr_find (struct c_map_int_ptr *, int key, void **data);
#ifdef __cplusplus
}
#endif

Затем код C ++ может реализовать такую ​​функцию:

typedef std::map<int, void *> map_int_ptr;

int c_map_int_ptr_find (struct c_map_int_ptr *cmap, int key, void **data) {
map_int_ptr &map = *static_cast<map_int_ptr *>(cmap);
map_int_ptr::iterator i = map.find(key);
if (i != map.end()) {
*data = i->second;
return 0;
}
return -1;
}

Таким образом, нет необходимости передавать аргументы, передаваемые через интерфейс C, через адаптер переменных аргументов. И поэтому нет необходимости в коде C ++ для выделения аргументов из списка переменных аргументов. Код C вызывает непосредственно код C ++, который знает, что делать с аргументами.

Я полагаю, что если вы пытаетесь реализовать какой-то автоматический генератор кода адаптера C, анализируя код C ++, вы можете подумать, что использование переменных аргументов обеспечит обычный механизм для передачи аргументов между сгенерированным интерфейсом кода C и сгенерированным кодом адаптера C ++, который будет вызовите оригинальный интерфейс C ++. Для такого сценария код для приведенного выше примера будет выглядеть примерно так:

// C interface
typedef struct c_map_int_ptr c_map_int_ptr;
typedef struct c_map_int_ptr_iterator c_map_int_ptr_iterator;
//...
c_map_int_ptr_iterator c_map_int_ptr_find (c_map_int_ptr *map, int key) {
c_map_int_ptr_iterator result;
cpp_map_int_ptr_adapter(__func__, map, key, &result);
return result;
}

// C++ code:
struct cpp_adapter {
virtual ~cpp_adapter () {}
virtual void execute (va_list) {}
};

void cpp_map_int_ptr_adapter(const char *func, ...) {
va_list ap;
va_start(ap, func);
cpp_map_int_ptr_adapter_method_lookup(func).execute(ap);
va_end(ap);
}

//...
struct cpp_map_int_ptr_find_adapter : cpp_adapter {
void execute (va_list ap) {
map_int_ptr *map = va_arg(ap, map_int_ptr *);
int key = va_arg(ap, int);
c_map_int_ptr_iterator *c_iter = va_arg(ap, c_map_int_ptr_iterator *);
map_int_ptr::iterator i = map->find(key);
//...transfer result to c_iter
}
};

куда cpp_map_int_ptr_adapter_method_lookup() возвращает соответствующий cpp_adapter экземпляр основан на поиске в таблице.

1

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector