У меня есть функция, которая берет блок данных и размер блока и указателя функции как аргумент. Затем это выполняет итерации по данным и выполняет вычисление на каждом элементе блока данных. Следующее является существенной схемой того, что я делаю:
int myfunction(int* data, int size, int (*functionAsPointer)(int)){
//walking through the data and calculating something
for (int n = 0; n < size; n++){
data[n] = (*function)(data[n]);
}
}
Функции я являюсь передающим как аргументы, выглядят примерно так:
int mycalculation(int input){
//doing some math with input
//...
return input;
}
Это работает хорошо, но теперь я должен передать дополнительную переменную своему functionpointer. Что-то вдоль строк
int mynewcalculation(int input, int someVariable){
//e.g.
input = input * someVariable;
//...
return input;
}
Существует ли изящный способ достигнуть этого и в то же время хранение моей идеи общего замысла?
Обычный способ сделать его полностью универсальным - использовать void *, что, конечно, вызывает всевозможные проблемы с безопасностью типов:
int map_function(int* data, int size, int (*f_ptr)(int, void*), void *userdata){
//walking through the data and calculating something
for (int n = 0; n < size; n++){
data[n] = (*f_ptr)(data[n], userdata);
}
}
int simple_calculation(int input, void *userdata) {
// ignore userdata and do some math with input
return input;
}
int calculation_with_single_extra_arg(int input, void *userdata) {
int input2 = * (int*) userdata;
// do some math with input and input2
return input;
}
int calculation_with_many_extra_args(int input, void *userdata) {
my_data_t data = (my_data_t *) userdata;
return input * (input * data->a + data->b) + data->c;
}
int main(int argc, char **argv) {
int array[100];
my_data_t userdata = { 1, 2, 3 };
populate(array, 100);
map_function(data, calculation_with_many_extra_args, &userdata);
}
Любая переданная функция должна у вас есть этот прототип, но вы можете вставить любые данные через userdata
. Здесь нет абсолютно никакой проверки типов.
Вы также можете использовать va_args, как предлагает dbingham; на самом деле это не сильно отличается, поскольку прототип для вашей функции для отображения должен быть int (int, va_list)
.
Редактировать: Я предпочитаю подход void *
. va_list
в любом случае не добавляет безопасности типов и увеличивает вероятность ошибки пользователя (в частности, вызов va_end
дважды или невыполнение правильного цикла va_arg
). Void * также не добавляет лишних строк кода; он прошел чисто, и пользователь просто разыменовывает его (надеюсь) на правильный тип (который, вероятно, является структурой в общем случае).