2011-07-08 14 views
5

मैं एक तंत्र तैयार कर रहा हूं जो अनुक्रम में यूनरी फ़ंक्शन ऑब्जेक्ट्स का एक सेट निष्पादित करेगा। इन फ़ंक्शन ऑब्जेक्ट रनटाइम के दौरान असाइन किए जाते हैं, और समस्या यह है: इन फ़ंक्शन ऑब्जेक्ट्स का पैरामीटर प्रकार अलग है।अनुक्रम में विभिन्न पैरामीटर प्रकार की यूनरी फ़ंक्शन ऑब्जेक्ट्स को निष्पादित करने के लिए कैसे करें?

मुझे क्या करना चाहते हैं कुछ इस तरह है:

class command_sequence { 
private: 

/* some kind of container */ 

public: 
    void add(FUNC_OBJ &func, PARAM val); 
    void run(void); 
}; 

class check_temperature { 
public: 
    void operator() (int celsius) { 
     if(celsius > 26) { 
      cooler.switch_on(); 
     } 
    } 
}; 

class log_usage { 
public: 
    void operator() (std::string username) { 
     username.append(" logged in"); 
     syslog(LOG_NOTICE,username.c_str()); 
    } 
}; 

command_sequence sequence; 
log_usage logger; 
check_temperature checker; 

sequence.add(logger, std::string("administrator")); 
sequence.add(checker, lobbyMeter.read_temperature()); 
sequence.add(logger, std::string("lecture")); 
sequence.add(checker, classroomMeter.read_temperature()); 
sequence.run(); 

मैं सी कोड लिख रहा हूँ, मैं कोई चारा नहीं कॉलबैक फ़ंक्शन सूचक है कि पैरामीटर के रूप में * शून्य लेता है। लेकिन अब मैं सी ++ के साथ काम कर रहा हूं, इसके साथ निपटने के लिए एक शानदार तरीका होना चाहिए।

सबसे अच्छा तरीका है मैं अब सोच सकते हैं एक टेम्पलेट वर्ग कि लगभग एक सार आवरण वर्ग से विरासत घोषित किया जाता है:

class command_sequence { 
private: 

    class runner { 
    public: 
     virtual void execute(void) = 0; 
    }; 

    template <class FUNC, typename T> class func_pair : public runner { 
    private: 
     FUNC &func; 
     T param; 
    public: 
     func_pair(FUNC &f, const T &t) : func(f),param(t) { } 
     void execute(void) { 
      func(param); 
     } 
    }; 

    std::vector<runner*> funcQueue; 

public: 

    template <class FUNC, typename T> void add(FUNC &obj, const T &t) { 
     funcQueue.push_back(new func_pair<FUNC,T>(obj,t)); 
    } 

    void run(void) { 
     std::vector<runner*>::iterator itr=funcQueue.begin(); 
     for(;itr!=funcQueue.end();++itr) { 
      (*itr)->execute(); 
      delete (*itr); 
     } 
    } 
}; 

यह दृष्टिकोण मेरी जरूरतों फिट कर सकते हैं, लेकिन यह आवंटन और प्रत्येक प्रविष्टि के लिए जारी template_pair होगा। मुझे नहीं पता कि इससे स्मृति खंड पैदा होगा, क्योंकि इस प्रक्रिया को प्रक्रिया के दौरान अक्सर बुलाया जाएगा।

क्या ऐसा करने का कोई बेहतर तरीका है?

उत्तर

4

ऐसा लगता है कि एकल कार्य करने के लिए तर्क बार जब आप अनुक्रम में जोड़ने पर तय हो गई है के बाद से, आप, तो boost::bind आवश्यक पैरामीटर बना सकता है आपके अनुक्रम boost::function का उपयोग कर शून्य तर्क समारोह वस्तुओं को स्वीकार करता है, उदा

class command_sequence { 
public: 
    void add(boost::function<void(void)> functor); 
}; 

/* ... as before ... */ 

log_usage logger; 
check_temperature checker; 

sequence.add(boost::bind<void>(logger, "administrator")); 
sequence.add(boost::bind<void>(checker, lobbymeter.read_temperature())); 

नोट आप के बाद से यह स्वचालित रूप से समारोह वस्तु की वापसी प्रकार अनुमान नहीं कर सकते <void>boost::bind कॉल करने के लिए एक टेम्पलेट पैरामीटर के रूप में निर्दिष्ट करने के लिए है। वैकल्पिक रूप से, आप एक सार्वजनिक typedef वर्ग परिभाषा जो इस से बचा जाता है में result_type कहा जाता है यानी बेनकाब कर सकते हैं,

class log_usage 
{ 
public: 
    typedef void result_type; 
    void operator() (const std::string& message) 
    { 
     // do stuff ... 
    } 
}; 

/* ... */ 

sequence.add(boost::bind(logger, "blah")); // will now compile 
+0

वास्तव में प्रभावशाली। मुझे नहीं पता कि बूस्ट :: बाइंड() फ़ंक्शन ऑब्जेक्ट्स को स्वीकार कर सकता है; लेकिन यह समझ में आता है। ऐसा लगता है कि मैं जिस जवाब की तलाश में हूं। धन्यवाद। – RichardLiu

7

क्या आपको वास्तव में फ़ंक्शन ऑब्जेक्ट और इसके तर्क को अलग से पास करने की आवश्यकता है? मैं इस मामले में boost::bind का उपयोग करेंगे, तो वह ऐसा दिखाई दे सकता है:

void check_temperature(int celsius) 
{ 
    if(celsius > 26) { 
     cooler.switch_on(); 
    } 
}; 

void log_usage(std::string username) 
{ 
    username.append(" logged in"); 
    syslog(LOG_NOTICE,username.c_str()); 
}; 

// keep actions 
typedef std::vector< boost::function<void()> > func_arr_t; 
func_arr_t actions; 
actions.push_back(boost::bind(&log_usage, "administrator")); 
actions.push_back(boost::bind(&check_temperature, lobbyMeter.read_temperature())); 
actions.push_back(boost::bind(&log_usage, "lecture")); 
actions.push_back(boost::bind(&check_temperature, classroomMeter.read_temperature())); 

// run all 
for (func_arr_t::const_iterator it = actions.begin(); it != actions.end(); ++it) 
    (*it)(); 

इस मामले command_sequence में सिर्फ समारोह में ऑब्जेक्ट की श्रृंखला रखेंगे।

+0

धन्यवाद, इस समाधान वास्तव में बढ़ावा के लिए एक मुहावरा है :: function(), लेकिन मैं एक वस्तु पारित करने के लिए आवश्यकता होगी मेरे मामले में उदाहरण। एक फंक्शन ऑब्जेक्ट को किसी अन्य वर्ग के भीतर समग्र कक्षा के रूप में घोषित किया जा सकता है, और इसमें कंटेनर क्लास के कुछ निजी सदस्य हो सकते हैं। उदाहरण के लिए, मेरे वास्तविक कोड में "check_temperature" फ़ंक्शन ऑब्जेक्ट में सदस्य चर के रूप में लक्ष्य "कूलर" को सॉकेट फ़ाइलिड भी होता है। – RichardLiu

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