Допустим, я создаю шахматную программу. У меня есть функция
void foreachMove( void (*action)(chess_move*), chess_game* game);
которая будет вызывать функцию-указатель action на каждом правильном ходу. Это все хорошо, но что если мне нужно передать больше параметров в функцию action? Например:
chess_move getNextMove(chess_game* game, int depth){
//for each valid move, determine how good the move is
foreachMove(moveHandler, game);
}
void moveHandler(chess_move* move){
//uh oh, now I need the variables "game" and "depth" from the above function
}
Переопределение указателя функции не является оптимальным решением. Функция foreachMove универсальна, и на нее ссылаются во многих местах кода. Не имеет смысла для каждой из этих ссылок обновлять свою функцию, чтобы включить параметры, которые им не нужны.
Как я могу передать дополнительные параметры в функцию, которую я вызываю через указатель?
Ах, если бы только C поддерживал закрытия...
Антонио прав; если вам нужно передать дополнительные параметры, вам придется переопределить указатель вашей функции, чтобы он мог принимать дополнительные аргументы. Если вы не знаете точно, какие параметры вам понадобятся, то у вас есть по крайней мере три варианта:
Вероятно, вам придется переопределить указатель функции, чтобы он мог принимать дополнительные аргументы.
void foreachMove( void (*action)(chess_move*, int), chess_game* game )
Если you' ре, готовое использовать некоторый C ++, Вы можете использовать " функция object":
struct MoveHandler {
chess_game *game;
int depth;
MoveHandler(chess_game *g, int d): game(g), depth(d) {}
void operator () (chess_move*) {
// now you can use the game and the depth
}
};
и поверните свой < code> foreachMove в шаблон:
template <typename T>
void foreachMove(T action, chess_game* game);
и Вы можете назвать его как это:
chess_move getNextMove(chess_game* game, int depth){
//for each valid move, determine how good the move is
foreachMove(MoveHandler(game, depth), game);
}
но это won' t разрушают Ваше другое использование < code> MoveHandler.
Если я правильно понял, то я бы предложил сделать так, чтобы ваша функция принимала в качестве аргумента указатель на struct. Тогда ваша структура может иметь "игру" и "глубину", когда они ей нужны, и просто оставить их установленными в 0 или Null, когда они вам не нужны.
Что происходит в этой функции? Есть ли у вас условие, которое говорит,
if (depth > -1) //some default
{
//do something
}
Всегда ли функция требует "игру" и "глубину"? Тогда они всегда должны быть аргументами, и это можно включить в прототипы.
Вы хотите сказать, что функция только иногда требует "игру" и "глубину"? Тогда, возможно, сделайте две функции и используйте каждую из них, когда это необходимо.
Но иметь структуру в качестве аргумента, вероятно, проще всего.
I' d предлагают использовать множество пустоты* с последним входом всегда пустота. скажите, что Вам нужны 3 параметра, Вы могли сделать это:
void MoveHandler (void** DataArray)
{
// data1 is always chess_move
chess_move data1 = DataArray[0]? (*(chess_move*)DataArray[0]) : NULL;
// data2 is always float
float data1 = DataArray[1]? (*(float*)DataArray[1]) : NULL;
// data3 is always char
char data1 = DataArray[2]? (*(char*)DataArray[2]) : NULL;
//etc
}
void foreachMove( void (*action)(void**), chess_game* game);
и затем
chess_move getNextMove(chess_game* game, int depth){
//for each valid move, determine how good the move is
void* data[4];
data[0] = &chess_move;
float f1;
char c1;
data[1] = &f1;
data[2] = &c1;
data[3] = NULL;
foreachMove(moveHandler, game);
}
Если все параметры - тот же тип тогда, Вы можете избежать, чтобы пустота* выстроила и просто послала ЗАКОНЧЕННОЕ ПУСТЫМ УКАЗАТЕЛЕМ множество любого типа, в котором Вы нуждаетесь.
+1 Антонио. Вы должны изменить свою декларацию указателя функции, чтобы принять дополнительные параметры.
Кроме того, пожалуйста, don' t начинают раздавать недействительные указатели или (особенно) множества недействительных указателей. That' s просто напрашивающийся на неприятности. Если Вы начинаете мимолетные недействительные указатели, you' ре, собирающееся также должным быть передать некоторое сообщение, чтобы указать на то, что тип указателя (или типы). Эта техника редко соответствующая.
Если Ваши параметры всегда - то же, просто добавьте их к своим аргументам указателя функции (или возможно упакуйте их в структуру и использование что как аргумент, если есть много параметров). Если Ваши параметры изменяют, то рассматривают использование нескольких указателей функции для сценариев селекторного совещания вместо мимолетных недействительных указателей.
Если бы Ваши параметры изменяются, я изменил бы декларацию указателя функции, чтобы использовать "..." техника, чтобы настроить переменное количество аргументов. Это могло спасти Вас в удобочитаемости и также имеющий необходимость внести изменение для каждого параметра, который Вы хотите передать к функции. Это определенно намного более безопасно, чем раздавание пустоты.
http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html
Просто к вашему сведению, о примере кода в связи: некоторые места, которые они имеют “n args” и другие, это - «n_args» с подчеркиванием. У них должно все быть подчеркивание. Я думал, что синтаксис выглядел немного забавным, пока я не понял, что они пропустили подчеркивание в некоторых местах.
Другой выбор состоял бы в том, чтобы изменить 'chess_move' структуру вместо прототипа функции. Структура уже, по-видимому, определена только в одном месте. Добавьте участников к структуре и заполните структуру соответствующими данными перед любым требованием, которое использует его.