2012-09-03 25 views
11

मैंने हाल ही में boost::program_options का उपयोग करना शुरू कर दिया है और इसे अत्यधिक सुविधाजनक पाया है। उस ने कहा, एक बात याद आ रही है कि मैं खुद को एक अच्छे तरीके से कोड करने में असमर्थ था:boost :: program_options: सभी विकल्पों को फिर से प्रिंट करना और प्रिंट करना

मैं स्क्रीन पर आउटपुट करने के लिए boost::program_options::variables_map में एकत्र किए गए सभी विकल्पों पर पुन: प्रयास करना चाहता हूं। यह एक सुविधाजनक फ़ंक्शन बनना चाहिए, जब मैं नए विकल्प जोड़ता हूं या प्रत्येक प्रोग्राम के लिए फ़ंक्शन को अपडेट करने की आवश्यकता के बिना सेट किए गए सभी विकल्पों को सूचीबद्ध करने के लिए बस कॉल कर सकता हूं।

मुझे पता है कि मैं व्यक्तिगत विकल्पों की जांच और आउटपुट कर सकता हूं, लेकिन ऊपर बताए अनुसार, यह एक सामान्य समाधान बनना चाहिए जो वास्तविक विकल्पों के लिए अनजान है। मैं आगे जानता हूं कि मैं variables_map की सामग्री पर पुन: प्रयास कर सकता हूं क्योंकि यह केवल std::map है। मैं तब संग्रहित boost::any परिवर्तनीय में शामिल प्रकार के प्रकार की जांच कर सकता हूं और इसे उचित प्रकार में परिवर्तित करने के लिए .as<> का उपयोग कर सकता हूं। लेकिन इसका मतलब यह होगा कि प्रत्येक प्रकार के लिए एक केस के साथ एक लंबे स्विच ब्लॉक को कोडिंग करना होगा। और यह मेरे लिए अच्छी कोडिंग शैली की तरह नहीं दिखता है।

तो सवाल यह है कि क्या इन विकल्पों पर पुन: प्रयास करने और उन्हें आउटपुट करने का एक बेहतर तरीका है?

उत्तर

5

विज़िटर पैटर्न का उपयोग करने के लिए यह एक अच्छा मामला है। दुर्भाग्यवश boost::anyboost::variant करता है जैसे विज़िटर पैटर्न का समर्थन नहीं करता है। फिर भी कुछ तीसरे पक्ष approaches हैं।

आरटीटीआई का उपयोग करने का एक और संभावित विचार है: हैंडलर फ़ैक्टर टाइप करने के लिए मैप किए गए ज्ञात प्रकारों के type_info का मानचित्र बनाएं।

+0

लिंक और RTTI के बारे में विचार करने के लिए धन्यवाद । मैं उम्मीद कर रहा था कि मैं सभी समर्थित प्रकारों के लिए एक संरचना बनाने से रोक सकता हूं जो कि प्रकारों में वृद्धि होने पर मुझे प्रबंधित करना होगा, लेकिन ऐसा लगता है कि यह संभव नहीं होगा। असल में, मैं इस प्रकार के हिरण को पास करना चाहता था - जैसे कि वे 'ऑपरेटर <<' का समर्थन करते हैं, सब कुछ ठीक काम करता है, अन्यथा संकलन विफल होना चाहिए। – shiin

5

जैसा कि पहले उल्लेख किया गया था, आगंतुक पैटर्न यहां एक अच्छी पसंद है। पीओ के साथ इसका उपयोग करने के लिए आपको अपने विकल्पों के लिए नोटिफ़ायर का उपयोग इस तरह से करने की आवश्यकता है कि यदि विकल्प पास किया गया नोटिफ़ायर boost::variant मानों के सेट में एक प्रविष्टि भर देगा। सेट अलग से संग्रहित किया जाना चाहिए। उसके बाद आप अपने सेट पर फिर से सक्रिय हो सकते हैं और boost::apply_visitor का उपयोग कर स्वचालित रूप से क्रियाओं (यानी प्रिंट) को संसाधित कर सकते हैं।

आगंतुकों के लिए, boost::static_visitor<>

से विरासत वास्तव में, मैं आगंतुक और सामान्य दृष्टिकोण उपयोग अधिक व्यापक बनाया है।

मैंने class MyOption बनाया है जिसमें मूल्य, boost::variant मूल्य और अन्य विकल्पों जैसे कि निहित, डिफ़ॉल्ट और अन्य के लिए विवरण है। मैं MyOption प्रकार के ऑब्जेक्ट्स के वेक्टर को उसी तरह से भरता हूं जैसे पीओ डू अपने विकल्पों के लिए (boost::po::options_add() देखें) टेम्पलेट्स के माध्यम से। std::string() या double()boosts::varian टी प्रारंभिकरण के लिए गुजरने के पल में आप मूल्य और अन्य चीजों जैसे डिफ़ॉल्ट, अंतर्निहित भरें।

इसके बाद मैंने boost::po::options_description कंटेनर भरने के लिए विज़िटर पैटर्न का उपयोग किया क्योंकि boost::po इनपुट कमांड लाइन को पार्स करने के लिए अपनी संरचनाओं की आवश्यकता है। भरने के दौरान मैंने प्रत्येक विकल्प के लिए अधिसूचना सेट की - यदि यह boost::po पारित हो जाएगा तो MyOption की मेरी मूल वस्तु स्वचालित रूप से भर जाएगी।

अगला आपको po::parse और po::notify निष्पादित करने की आवश्यकता है। इसके बाद आप विज़िटर पैटर्न के माध्यम से पहले ही भरे std::vector<MyOption*> का उपयोग करने में सक्षम होंगे क्योंकि इसमें बूस्ट :: संस्करण शामिल है।

इस सब के बारे में क्या अच्छा है - आपको कोड में केवल एक बार अपना विकल्प टाइप लिखना होगा - जब आप std::vector<MyOption*> भरते हैं।

पीएस। यदि इस दृष्टिकोण का उपयोग करते हुए आपको किसी विकल्प के लिए अधिसूचना सेट करने की समस्या का सामना करना पड़ेगा, तो समाधान प्राप्त करने के लिए इस विषय का संदर्भ लें: boost-program-options: notifier for options with no value

PS2। कोड का उदाहरण:

std::vector<MyOptionDef> options; 
OptionsEasyAdd(options) 
    ("opt1", double(), "description1") 
    ("opt2", std::string(), "description2") 
... 
; 
po::options_descripton boost_descriptions; 
AddDescriptionAndNotifyerForBoostVisitor add_decr_visitor(boost_descriptions); 
// here all notifiers will be set automatically for correct work with each options' value type 
for_each(options.begin(), options.end(), boost::apply_visitor(add_descr_visitor)); 
+0

पूरी तरह से स्पष्टीकरण के लिए धन्यवाद। यह भी एक दिलचस्प समाधान है। इस तरह से मैं आसानी से सहायता आउटपुट के लिए अलग-अलग विवरण जोड़ सकता हूं और जब विकल्प मानों को सूचीबद्ध करता हूं। – shiin

0

मैं आज इस तरह की समस्या से निपट रहा था। यह एक पुराना सवाल है, लेकिन शायद यह उन लोगों की मदद करेगा जो उत्तर की तलाश में हैं।

जिस विधि के साथ मैं आया था वह < ...>() के गुच्छा को आजमाएं और फिर अपवाद को अनदेखा करें। यह बहुत सुंदर नहीं है, लेकिन मुझे यह काम करने के लिए मिला।

नीचे कोड ब्लॉक में, vm boost program_options से एक variables_map है। विट वीएम पर एक इटरेटर है, जो इसे std :: string और boost :: program_options :: variable_value की एक जोड़ी बनाता है, बाद वाला कोई बढ़ावा :: कोई भी है। मैं वैरिएबल के नाम को पहले- vit के साथ प्रिंट कर सकता हूं, लेकिन विट-> दूसरा आउटपुट के लिए इतना आसान नहीं है क्योंकि यह एक बढ़ावा है :: कोई भी, यानी मूल प्रकार खो गया है। कुछ को std :: स्ट्रिंग के रूप में डाला जाना चाहिए, कुछ डबल के रूप में, और इसी तरह।

तो, चर का मान अदालत के लिए, मैं इस का उपयोग कर सकते हैं:

std::cout << vit->first << "="; 
try { std::cout << vit->second.as<double>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<int>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<std::string>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<bool>() << std::endl; 
} catch(...) {/* do nothing */ } 

मैं केवल 4 प्रकार है कि मैं कमांड लाइन/config फ़ाइल से जानकारी प्राप्त करने के लिए उपयोग किया है, अगर मैं और अधिक जोड़ा प्रकार, मुझे और लाइनें जोड़नी होंगी। मैं स्वीकार करूंगा कि यह थोड़ा बदसूरत है।

0

चूंकि आप उन्हें प्रिंट करने जा रहे हैं, वैसे भी आप पर्स करते समय मूल स्ट्रिंग प्रस्तुति को पकड़ सकते हैं। (संभावना वहाँ कोड में संकलक त्रुटियाँ हैं, मैं इसे अपने codebase और चीजों की अन-typedefed गुच्छा से बाहर फट)

std::vector<std::string> GetArgumentList(const std::vector<boost::program_options::option>& raw) 
{ 
    std::vector<std::string> args; 

    BOOST_FOREACH(const boost::program_options::option& option, raw) 
    { 
     if(option.unregistered) continue; // Skipping unknown options 

     if(option.value.empty()) 
      args.push_back("--" + option.string_key)); 
     else 
     { 
      // this loses order of positional options 
      BOOST_FOREACH(const std::string& value, option.value) 
      { 
       args.push_back("--" + option.string_key)); 
       args.push_back(value); 
      } 
     } 
    } 

    return args; 
} 

उपयोग:

boost::program_options::parsed_options parsed = boost::program_options::command_line_parser(... 

std::vector<std::string> arguments = GetArgumentList(parsed.options); 
// print