2008-08-14 18 views
9

में अधिक पैरामीटर पास करना मान लें कि मैं एक शतरंज प्रोग्राम बना रहा हूं। मेरे पास एक समारोह हैसी फ़ंक्शन पॉइंटर्स

void foreachMove(void (*action)(chess_move*), chess_game* game); 

जो प्रत्येक मान्य चाल पर फ़ंक्शन पॉइंटर कार्रवाई को कॉल करेगा। यह सब ठीक है और अच्छा है, लेकिन अगर मुझे एक्शन फ़ंक्शन में अधिक पैरामीटर पास करने की आवश्यकता है तो क्या होगा? उदाहरण के लिए:

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 फ़ंक्शन बहुमुखी है और कोड संदर्भ में कई अलग-अलग स्थान हैं। उन संदर्भों में से प्रत्येक के लिए उनके फ़ंक्शन को अपडेट करने के लिए यह समझ में नहीं आता है कि उन पैरामीटर को शामिल करने के लिए जिन्हें उनकी आवश्यकता नहीं है।

मैं एक ऐसे फ़ंक्शन पर अतिरिक्त पैरामीटर कैसे पास कर सकता हूं जिसे मैं पॉइंटर के माध्यम से कॉल कर रहा हूं?

उत्तर

8

आपको अतिरिक्त तर्क लेने के लिए फ़ंक्शन पॉइंटर को फिर से परिभाषित करने की आवश्यकता होगी।

void foreachMove(void (*action)(chess_move*, int), chess_game* game) 
11

आह, अगर केवल सी समर्थित बंद ...

एंटोनियो सही है; यदि आपको अतिरिक्त पैरामीटर पास करने की आवश्यकता है, तो आपको अतिरिक्त तर्क स्वीकार करने के लिए अपने फ़ंक्शन पॉइंटर को फिर से परिभाषित करने की आवश्यकता होगी। यदि आपको पता नहीं है कि आपको किन पैरामीटर की आवश्यकता होगी, तो आपके पास कम से कम तीन विकल्प हैं:

  1. क्या आपके प्रोटोटाइप में अंतिम तर्क शून्य है *। इससे आपको किसी और चीज में गुज़रने की लचीलापन मिलती है, लेकिन यह निश्चित रूप से टाइप-सुरक्षित नहीं है।
  2. विविधता पैरामीटर (...) का उपयोग करें। सी में वैरिएडिक पैरामीटर के साथ अनुभव की कमी को देखते हुए, मुझे यकीन नहीं है कि आप इसे फ़ंक्शन पॉइंटर के साथ उपयोग कर सकते हैं, लेकिन यह पहले समाधान की तुलना में और अधिक लचीलापन देता है, यद्यपि प्रकार की सुरक्षा की कमी के बावजूद।
  3. सी ++ में अपग्रेड करें और function objects का उपयोग करें।
3

यदि मैं यह सही पढ़ रहा हूं, तो मैं सुझाव दूंगा कि आपके कार्य को एक तर्क के रूप में एक संरचना के लिए एक सूचक को लेना है। फिर, जब आपकी आवश्यकता होती है तो आपकी संरचना में "गेम" और "गहराई" हो सकती है, और जब उन्हें आवश्यकता नहीं होती है तो उन्हें केवल 0 या नल पर सेट करें।

उस समारोह में क्या चल रहा है? क्या आपके पास एक सशर्त है जो कहता है,

if (depth > -1) //some default 
    { 
    //do something 
    } 

क्या फ़ंक्शन हमेशा "गेम" और "गहराई" की आवश्यकता है? फिर, उन्हें हमेशा तर्क होना चाहिए, और यह आपके प्रोटोटाइप में जा सकता है।

क्या आप इंगित करते हैं कि फ़ंक्शन को कभी-कभी "गेम" और "गहराई" की आवश्यकता होती है? खैर, शायद दो कार्य करें और जब आपको आवश्यकता हो तो प्रत्येक का उपयोग करें।

लेकिन, तर्क के रूप में संरचना होने के कारण शायद सबसे आसान बात है।

6

आप कुछ सी ++ उपयोग करने के लिए तैयार हैं, तो आप एक "समारोह वस्तु" का उपयोग कर सकते हैं:

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 
    } 
}; 

और एक टेम्पलेट में अपने 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); 
} 

लेकिन यह MoveHandler के अपने अन्य उपयोगों को बाधित नहीं होगा।

1

मैं अंतिम प्रविष्टि हमेशा शून्य के साथ शून्य * की एक सरणी का उपयोग करने का सुझाव दूंगा।

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); 
} 

सभी मापदंडों एक ही प्रकार के हैं तो आप शून्य * सरणी से बच सकते हैं और सिर्फ एक शून्य-समाप्त भेजें: आप 3 मानकों की जरूरत है आप ऐसा कर सकता है कहना आपको जिस प्रकार की आवश्यकता है उसकी सरणी।

0

+1 एंटोनियो को +1। अतिरिक्त पैरामीटर स्वीकार करने के लिए आपको अपने फ़ंक्शन पॉइंटर घोषणा को बदलने की आवश्यकता है।

इसके अलावा, कृपया शून्य पॉइंटर्स या (विशेष रूप से) शून्य पॉइंटर्स के सरणी पास करना शुरू न करें। यह सिर्फ परेशानी के लिए पूछ रहा है। यदि आप शून्य पॉइंटर्स को गुजरना शुरू करते हैं, तो आपको इंगित करने के लिए कुछ प्रकार का संदेश भी देना होगा कि पॉइंटर प्रकार क्या है (या प्रकार हैं)। यह तकनीक है शायद उपयुक्त।

अपने मानकों को हमेशा एक ही कर रहे हैं, बस उन्हें अपने कार्य सूचक तर्क को जोड़ने के (या शायद उन्हें एक struct में पैक और प्रयोग है कि तर्क के रूप में अगर वहाँ मापदंडों के एक बहुत हैं)। यदि आपके पैरामीटर बदलते हैं, तो शून्य पॉइंटर्स पास करने के बजाय एकाधिक कॉल परिदृश्यों के लिए एकाधिक फ़ंक्शन पॉइंटर्स का उपयोग करने पर विचार करें।

0

यदि आपके पैरामीटर बदलते हैं, तो मैं फ़ंक्शन पॉइंटर घोषणा को "..." तकनीक का उपयोग करने के लिए तर्कों की एक चर संख्या सेट करने के लिए बदल दूंगा। यह आपको पठनीयता में सहेज सकता है और प्रत्येक पैरामीटर के लिए भी बदलाव कर सकता है जिसे आप फ़ंक्शन में पास करना चाहते हैं। यह शून्य के पास गुजरने से निश्चित रूप से बहुत सुरक्षित है।

http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html

बस एक FYI करें, लिंक में उदाहरण कोड के बारे में: कुछ स्थानों वे "n आर्ग" और दूसरों है यह अंडरस्कोर के साथ "n_args" है। वे सभी अंडरस्कोर होना चाहिए। मैंने सोचा कि वाक्यविन्यास थोड़ा मजाकिया लग रहा था जब तक मुझे एहसास हुआ कि उन्होंने कुछ जगहों पर अंडरस्कोर गिरा दिया था।

0

एक और विकल्प फ़ंक्शन प्रोटोटाइप के बजाय chess_move संरचना को संशोधित करना होगा। संरचना को संभवतः पहले से ही एक ही स्थान पर परिभाषित किया गया है। सदस्यों को संरचना में जोड़ें, और किसी भी कॉल का उपयोग करने से पहले उचित डेटा के साथ संरचना को भरें।

संबंधित मुद्दे