Let's mengatakan saya'm menciptakan program catur. Saya memiliki fungsi
void foreachMove( void (*action)(chess_move*), chess_game* game);
yang akan memanggil fungsi pointer tindakan pada setiap langkah yang valid. Ini semua baik dan bagus, tapi bagaimana jika saya perlu untuk lulus lebih parameter untuk fungsi action? Misalnya:
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
}
Mendefinisikan fungsi pointer adalah bukan solusi yang optimal. Yang foreachMove fungsi serbaguna dan banyak tempat-tempat yang berbeda di kode referensi. Itu doesn't masuk akal untuk masing-masing dari referensi tersebut harus memperbarui fungsi untuk memasukkan parameter bahwa mereka don't perlu.
Bagaimana saya bisa lulus parameter tambahan untuk fungsi yang saya'm panggilan melalui pointer?
Ah, kalau saja C didukung penutupan...
Antonio adalah benar; jika anda perlu untuk melewati parameter tambahan, anda'll perlu untuk mendefinisikan fungsi pointer untuk menerima argumen tambahan. Jika anda don't tahu persis apa parameter anda'll butuhkan, maka anda memiliki setidaknya tiga pilihan:
Jika anda're bersedia menggunakan C++, anda dapat menggunakan "fungsi objek":
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
}
};
dan giliran anda foreachMove
ke template:
template <typename T>
void foreachMove(T action, chess_game* game);
dan anda dapat menyebutnya seperti ini:
chess_move getNextMove(chess_game* game, int depth){
//for each valid move, determine how good the move is
foreachMove(MoveHandler(game, depth), game);
}
tapi itu tidak't mengganggu kegunaan lain dari MoveHandler
.
Jika saya'm membaca ini benar, apa yang saya'd sarankan adalah untuk membuat fungsi anda mengambil pointer ke struct sebagai argumen. Kemudian, anda struct dapat memiliki "permainan" dan "dalam" ketika kebutuhan mereka, dan hanya meninggalkan mereka di set ke 0 atau Null ketika anda don't membutuhkan mereka.
Apa yang terjadi di dalam fungsi itu? Apakah anda memiliki bersyarat yang mengatakan,
if (depth > -1) //some default
{
//do something
}
Apakah fungsi selalu MEMBUTUHKAN "permainan" dan "dalam"? Kemudian, mereka harus selalu menjadi argumen, dan yang dapat masuk ke dalam prototipe.
Apakah anda menunjukkan bahwa fungsi hanya kadang-kadang membutuhkan "permainan" dan "dalam"? Yah, mungkin membuat dua fungsi dan penggunaan masing-masing ketika anda perlu.
Tapi, memiliki struktur sebagai argumen mungkin adalah hal yang paling mudah.
I'd sarankan untuk menggunakan sebuah array dari void*, dengan entri terakhir selalu batal. katakanlah anda membutuhkan 3 parameter yang anda bisa lakukan ini:
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);
dan kemudian
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);
}
Jika semua parameter adalah tipe yang sama maka anda dapat menghindari kekosongan* array dan hanya mengirim sebuah NULL-terminated para apapun jenis yang anda butuhkan.
+1 untuk Antonio. Anda perlu untuk mengubah anda fungsi pointer deklarasi untuk menerima parameter tambahan.
Juga, silakan don't mulai lewat di sekitar void pointer atau (terutama) array void pointer. Yang's hanya meminta masalah. Jika anda mulai melewati void pointer, anda're akan juga harus melewati beberapa jenis pesan untuk menunjukkan apa jenis pointer (atau jenis). Teknik ini jarang yang tepat.
Jika anda parameter yang selalu sama, hanya menambahkan mereka ke penunjuk fungsi argumen (atau mungkin paket mereka ke dalam sebuah struct dan menggunakannya sebagai argumen jika ada banyak parameter). Jika anda perubahan parameter, maka pertimbangkan untuk menggunakan beberapa fungsi pointer untuk beberapa skenario panggilan bukan lewat void pointer.
Jika anda parameter perubahan, saya akan mengubah fungsi pointer deklarasi untuk menggunakan "..." teknik untuk mengatur variabel jumlah argumen. Itu bisa menyelamatkan anda di mudah dibaca dan juga bisa untuk membuat perubahan untuk masing-masing parameter yang anda inginkan untuk lolos ke fungsi. Itu pasti jauh lebih aman daripada lewat batal sekitar.
http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html
Just FYI, tentang contoh kode di link: beberapa tempat yang telah mereka "n args" dan lain-lain itu adalah "n_args" dengan underscore. Mereka semua harus memiliki garis bawah. Saya pikir sintaks tampak sedikit lucu sampai saya menyadari bahwa mereka telah menjatuhkan garis bawah di beberapa tempat.
Menggunakan typedef untuk fungsi pointer. Melihat saya jawaban pertanyaan
Pilihan lain akan mengubah chess_move
struktur bukan prototipe fungsi. Struktur adalah mungkin didefinisikan hanya dalam satu tempat yang sudah. Menambahkan anggota ke struktur, dan isi dengan struktur data yang sesuai sebelum setiap panggilan yang menggunakannya.