В C++ функция с переменным числом аргументов шаблоны с переменным числом аргументов макроса
В настоящее время я работаю над проектом, в котором мне нужно упростить существующую систему.
Не вдаваясь в детали, проблема заключается в том, что я получаю некоторый указатель функции (от типа: void*), и мне нужно создать функцию из него (= create a function with signature). Так что мой подход заключался в том, чтобы создать следующий шаблон функции с переменным числом аргументов:
template <typename ReturnType, typename ... Params>
ReturnType(*GetFunction(void* func, Params ...)) (Params ...)
{
return reinterpret_cast<ReturnType(*) (Params ...)> (func);
}
Теперь мне нужен способ создать необходимые функции:
#define DECLARE_PARAMS(...) __VA_ARGS__
#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)
{
return FUNCTION_DIRECTCALL(returnType, fname, (DECLARE_PARAMS Params));
}
И вот в чем проблема. (Я думаю) Парамы не расширяются так, как они должны расширить. Но я не знаю почему.
Я протестировал FUNCTION_DIRECTCALL в макросе DEFINE_FUNCTION с жестко заданными значениями (просто поместите определение в directcall), и это сработало, так что ошибки быть не должно, но я открыт для улучшений
#define FUNCTION_DIRECTCALL(returnType, functionName, ...)
GetFunction<returnType>(functionName, DECLARE_PARAMS __VA_ARGS__) ( DECLARE_PARAMS __VA_ARGS__)
Если я попытаюсь определить функцию с помощью макроса
Define_Function(void, ThatFunction, (int a_, int b_)); // void ThatFunction(int a, int b);
Я получаю следующую ошибку: "описание кода серьезности ошибка состояния подавления строки файла проекта (Активный) неполный тип не допускается [...]главный.cpp 34 "
Итак, мой вопрос в том, что я делаю не так? Действительно ли проблема связана с парами в макросе DEFINE_FUNCTION или я что-то пропустил?
Я работал с макросами, но я бы не назвал себя экспертом в этой области. Но я так понимаю, что (DECLARE_PARAMS Params) должен расширить params до:
int a_, int b_
И после сканирования я ожидал бы следующий код:
void Gen_ThatFunction(int a_, int b_)
{
return GetFunction<void>(ThatFunction, a_, b_) (a_, b_);
}
Тестирование макроса Directcall:
с помощью следующего кода я протестировал функциональность макроса directcall
Поэтому я изменяю макрос Define_Function:
#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)
{
int a = 2, b = 3;
return FUNCTION_DIRECTCALL(void, ThatFunction, (a, b) );
}
Определение этой функции:
void ThatFunction(int a, int b)
{
std::cout << a << " * " << b << " = " << b * a << std::endl;
}
Вывод: "2 * 3 = 6"
Весь код, скомпилированный в VC++ 2015
1 ответ:
Единственный способ, который я знаю, как сделать то, о чем вы просите, - это действительно неуклюжий.
#define DEFINE_FUNCTION(RET, NAME, TYPES, NAMES, BOTH) RET Gen_##NAME BOTH { return reinterpret_cast<RET(*)TYPES>(NAME) NAMES; }Вы используете его как:
DEFINE_FUNCTION(void, ThatFunction, (int, int), (a_, b_), (int a_, int b_))Возвращаемый тип и имя
void*(или функции) являются первыми двумя параметрами. Далее следует список типов аргументов, заключенный в скобки, имена аргументов, заключенные также, и, наконец, заключенные типы и имена. Как я уже сказал, неуклюжий.Это будет генерировать функцию:
void Gen_ThatFunction (int a_, int b_) { return reinterpret_cast<void(*)(int, int)>(ThatFunction) (a_, b_); }Затем вы можете вызвать функцию, как вы желание:
Gen_ThatFunction(2, 3); //prints "2 * 3 = 6"Конечно, имейте в виду, что это специфика Microsoft. Здесь элементы, разделенные запятыми и заключенные в скобки, являются одним макропараметром. На любом другом компиляторе это не сработало бы (что я знаю).
Comments