2012-04-06 11 views
19

उदाहरण के लिए here पर चर्चा के रूप में सी ++ में परिवर्तनीय तर्कों के साथ एक फ़ंक्शन रखने के लिए मुझे पहले से ही stdarg.h तरीका पता है। मुझे यह भी पता है कि सी ++ 11 मानक में विविधता टेम्पलेट्स हैं जैसा कि here समझाया गया है।ज्ञात प्रकारों के साथ तर्कों की परिवर्तनीय संख्या वाला एक फ़ंक्शन, सी ++ 11 रास्ता

लेकिन उपर्युक्त योजनाओं में हम दोनों को संकलित समय में संकलित प्रकारों (और हम बल नहीं दे सकते) में नहीं जानते हैं। जो मैं खोज रहा हूं वह के परिवर्तनीय तर्कों को पास करने के लिए ज्ञात प्रकारों को पास करना है। मैं इस क्योंकि मैं इसे here के बारे में पढ़ा किया जा सकता है लगता है:

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

क्या यह संभव है? यदि हां, तो मैं यह कैसे कर सकता हूं?

उत्तर

30

यह भिन्नता वाले टेम्पलेट्स के साथ एक फ़ंक्शन लिखने के लिए सीधे आगे है, जो तर्कों की मनमानी संख्या स्वीकार करता है। सामान्य पैटर्न में एकमात्र अंतर यह है कि एक ठोस प्रकार का उपयोग पहले तर्क (सिर) के रूप में किया जाता है - टेम्पलेट पैरामीटर के बजाय। निम्न उदाहरण एक फ़ंक्शन foobar दिखाता है, जो तारों की मनमानी संख्या स्वीकार करता है।

// used for end of recursion - and for the empty arguments list 
void foobar() { } 

template <typename ...Tail> 
void foobar(const std::string& head, Tail&&... tail) 
{ 
    // do something with head 
    std::cout << head << '\n'; 
    // call foobar recursively with remaining arguments 
    foobar(std::forward<Tail>(tail)...); 
} 

foobar("Hello", "World", "..."); 

व्यक्तिगत रूप से, मैं विविधता टेम्पलेट्स के बजाय std::initializer_list का उपयोग करना पसंद करता हूं। क्योंकि विविध टेम्पलेट्स अधिक जटिल हैं और अतिरिक्त अनुभव की आवश्यकता है। std::initializer_list के साथ, यह इस प्रकार दिखाई देंगे:

void foobar(std::initializer_list<std::string> values) 
{ 
    for (auto& value : values) { 
     // do something with value 
     std::cout << value << '\n'; 
    } 
} 

foobar({ "Hello", "World", "...", }); 

दुर्भाग्य से, अतिरिक्त घुंघराले ब्रेसिज़ के लिए आवश्यक हैं जब नियमित कार्यों के साथ std::initializer_list का उपयोग कर। यदि नए प्रारंभकर्ता सिंटैक्स का उपयोग किया जाता है, तो उन्हें रचनाकारों के लिए आवश्यक नहीं है।

संपादित करें: प्रतिक्रिया के अनुसार उत्तर दोबारा जवाब दें। विशेष रूप से मैंने दो समाधान/उदाहरणों का क्रम बदल दिया है।

+1

मुझे लगता है कि यह मेरी गलतफहमी के बारे में था। मैं दूसरी तरफ जानता था, लेकिन मैंने हमेशा सोचा कि पैरामीटर के प्रकार पर कोई नियंत्रण नहीं है। यह सच नहीं है। क्योंकि फ़ंक्शन किसी ज्ञात प्रकार का पहला पैरामीटर लेता है (यहां स्ट्रिंग), यह निश्चित रूप से उस प्रकार के पैरामीटर रखने के लिए मजबूर है। धन्यवाद। – melmi

+2

आप पहले दूसरे कोड-बॉक्स को स्थानांतरित करना चाहते हैं। यह समस्या का एक बहुत अच्छा समाधान है, जबकि 'startizer_list' संस्करण नहीं है। मैं SFINAE और इस तरह के साथ एक बड़ी, जटिल चीज पोस्ट करने जा रहा था, लेकिन यह कहीं अधिक उचित है। –

+0

@nosid आप वास्तव में घुंघराले ब्रेसिज़ का उपयोग करने से बच सकते हैं यदि आप std :: startizer_list और variadic टेम्पलेट दृष्टिकोण दोनों को मिश्रित करते हैं, तो std ::itializer_list संस्करण के चारों ओर एक भिन्न टेम्पलेट रैपर बनाकर, इस तरह: [coliru पर देखें] (http: //coliru.stacked-crooked.com/a/4baef67192a0310c)। –

2

यदि परिवर्तनीय पैरामीटर एक ही प्रकार के हैं, तो आप '...' का उपयोग करने के बजाय उन प्रकारों की सरणी लेने के लिए फ़ंक्शन हस्ताक्षर बदल सकते हैं।

+0

एक प्रकार की एक सरणी को पुनरावृत्ति की आवश्यकता होती है, जबकि विविधता कार्यों का उपयोग एक संकलित समय इनलाइन तंत्र प्रदान करता है। आप कह सकते हैं कि एक सरणी पर लूपिंग इतना समय नहीं है, लेकिन इसे एक और कई बड़े लूप में मानें। – melmi