2012-05-17 31 views
13

का उपयोग करके मेटाप्रोग्रामिंग सी/सी ++ तो मेरे पास यह विशाल पेड़ है जो मुख्य रूप से स्ट्रिंग कुंजियों के साथ एक बड़ा स्विच/मामला है और कुंजी और मेटाडाटा के एक टुकड़े के आधार पर एक सामान्य वस्तु पर अलग-अलग फ़ंक्शन कॉल होता है।प्रीप्रोसेसर

प्रत्येक प्रविष्टि मूल रूप से इस

} else if (strcmp(key, "key_string") == 0) { 
    ((class_name*)object)->do_something(); 
} else if (... 

do_something अलग आमंत्रण हो सकता है जहां की तरह दिखता है, तो मैं बस समारोह संकेत का उपयोग नहीं कर सकते हैं। इसके अलावा, कुछ कुंजियों को वस्तु को उप-वर्ग में डालने की आवश्यकता होती है।

अब, अगर मैं इसे उच्च स्तर की भाषा में कोड करना चाहता हूं, तो मैं इसे सरल बनाने के लिए लैम्बडा के शब्दकोश का उपयोग करूंगा।

ऐसा नहीं है कि मैं की तरह

case_call("key_string", class_name, do_something()); 
case_call(/* ... */) 

कुछ को यह आसान बनाने के लिए जहां case_call एक मैक्रो है कि पहले कोड स्निपेट के लिए इस कोड का विस्तार होगा मैक्रो का उपयोग कर सकता है मेरे लिए हुई।

हालांकि, मैं बाड़ पर बहुत अधिक हूं कि क्या इसे अच्छी शैली माना जाएगा। मेरा मतलब है, यह टाइपिंग काम को कम करेगा और कोड की ड्रवाईनेस में सुधार करेगा, लेकिन फिर यह वास्तव में मैक्रो सिस्टम का दुरुपयोग करने लगता है।

क्या आप उस सड़क पर उतरेंगे, या पूरी चीज टाइप करेंगे? और ऐसा करने के लिए आपका तर्क क्या होगा?

संपादित

कुछ स्पष्टीकरण:

इस कोड को एक सरल पटकथा एपीआई जो एक सी ++ एपीआई के रूप में सरल कुंजी-मान गुण के कई विभिन्न पहलुओं तक पहुँचता है जो गोंद परत के रूप में प्रयोग किया जाता है। संपत्तियों को सी ++ में विभिन्न तरीकों से लागू किया गया है हालांकि: कुछ में गेटर/सेटर विधियां हैं, कुछ विशेष संरचना में सेट हैं। स्क्रिप्टिंग क्रियाओं का संदर्भ सी ++ ऑब्जेक्ट्स को एक सामान्य बेस क्लास में डाला जाता है। हालांकि, कुछ क्रियाएं केवल कुछ उप-वर्गों पर उपलब्ध हैं और उन्हें नीचे डालना होगा।

सड़क के नीचे आगे, मैं वास्तविक सी ++ एपीआई बदल सकता हूं, लेकिन इस पल के लिए, इसे अपरिवर्तनीय माना जाना चाहिए। इसके अलावा, इसे एक एम्बेडेड कंपाइलर पर काम करना है, इसलिए बूस्ट या सी ++ 11 (दुखी) उपलब्ध नहीं हैं।

+5

क्यों वोट बंद करने के लिए - यह एक बहुत अच्छा, वैध सवाल है। मुझे यहां क्या समझ नहीं आ रहा है? –

+3

यह एक अच्छा सवाल है, लेकिन "यह सवाल हमारे प्रश्नोत्तर प्रारूप हम जवाब आम तौर पर तथ्यों, संदर्भ, या विशिष्ट विशेषज्ञता को शामिल करने की उम्मीद करना एक अच्छा फिट नहीं है,। * इस सवाल की संभावना मांगना होगा राय, बहस, तर्क, मतदान, या बढ़ाया चर्चा। * " – Fanael

+0

यह पहले से ही +5 स्कोर पर है, इसलिए थोड़े कहता है कि दूसरों ने स्वयं को शामिल किया है, परिणाम में रुचि रखते हैं। नीचे दिया गया जवाब पहले से ही बहुत अच्छा है। –

उत्तर

6

मेरा सुझाव है कि आप थोड़ा भूमिकाओं रिवर्स। आप कह रहे हैं कि ऑब्जेक्ट पहले से ही कुछ वर्ग है जो जानता है कि किसी निश्चित स्थिति को कैसे संभालना है, इसलिए अपनी बेस क्लास में virtual void handle(const char * key) जोड़ें और ऑब्जेक्ट को कार्यान्वयन में जांचें यदि यह उस पर लागू होता है और जो भी आवश्यक हो।

यह केवल लंबे समय तक अगर-बाकी-अगर श्रृंखला को खत्म करेगा नहीं, लेकिन यह भी अधिक प्रकार सुरक्षित हो सकता है और उन घटनाओं से निपटने में आपको अधिक विकल्प होगा।

+0

यह लंबे समय तक खत्म नहीं होता है, अगर श्रृंखला है, तो यह केवल इसे स्थानांतरित/पुनर्व्यवस्थित करता है। हालांकि, यह अभी भी एक बहुत अच्छा विचार है। –

+1

@MooingDuck यह व्यक्तिगत ifs को खत्म नहीं करेगा, लेकिन यह उन मामलों की केंद्रीय, लंबी सूची को खत्म कर देगा जिन्हें संभालना है। प्रत्येक चेक कक्षा में होगी जहां वास्तविक हैंडलिंग होती है, इसलिए नई कार्यक्षमता जोड़ने के लिए जो स्थान बदलना है, वे एक साथ बंद हो जाएंगे। – Fozi

+0

यह एक दिलचस्प विचार है। मुझे कार्यान्वयन कक्षाओं को संशोधित करने की आवश्यकता होगी, जो कि कई कारणों से अभी वांछनीय नहीं है, लेकिन यह निश्चित रूप से एक अच्छा विचार है। – bastibe

6

मुझे मैक्रोज़ का उचित उपयोग लगता है। वे सब के बाद, सिंटेक्टिक पुनरावृत्ति eliding के लिए बनाया गया है। हालांकि, जब आपके पास वाक्य रचनात्मक पुनरावृत्ति होती है, तो यह हमेशा भाषा की गलती नहीं होती है- वहां शायद बेहतर डिज़ाइन विकल्प होते हैं जो आपको इस निर्णय से पूरी तरह से बचने देते हैं।

std::map<std::string, void(Class::*)()> table; 

फिर देखो और एक ही बार में कार्रवाई आह्वान:

object->*table[key](); 

या find का उपयोग विफलता के लिए जाँच करने के लिए

सामान्य ज्ञान कार्रवाई करने के लिए एक मेज मानचित्रण कुंजी का उपयोग करने के लिए है:

const auto i = table.find(key); 
if (i != table.end()) 
    object->*(i->second)(); 
else 
    throw std::runtime_error(...); 

लेकिन यदि आप कहते हैं कि कार्यों के लिए कोई आम हस्ताक्षर नहीं है (यानी, आप सदस्य फ़ंक्शन पॉइंटर्स का उपयोग नहीं कर सकते हैं) तो आप वास्तव में करना चाहिए, जो आपके प्रोजेक्ट के विवरणों पर निर्भर करता है, जो मुझे नहीं पता। ऐसा हो सकता है कि एक मैक्रो आपके द्वारा देखे जा रहे पुनरावृत्ति को दूर करने का एकमात्र तरीका है, या हो सकता है कि इसके बारे में जाने का एक बेहतर तरीका हो।

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

+0

"जहां do_something में अलग-अलग आमंत्रण हो सकते हैं, इसलिए मैं फ़ंक्शन पॉइंटर्स का उपयोग नहीं कर सकता।" <- ऐसा लगता है कि सभी कार्य 'शून्य (कक्षा :: *)() 'होने जा रहे हैं। कुछ को तर्क की आवश्यकता हो सकती है। कम से कम यही मुझे समझ में आया। – mfontanini

+0

@ फोंटानिनी: आह, याद किया। संपादित करेंगे –

+0

असल में, मेरे पास दो अलग-अलग प्रकार के आमंत्रण हैं, इसलिए यदि मैं दो मानचित्रों का उपयोग करता तो यह वास्तव में काम करेगा। – bastibe