2011-11-18 16 views
8

इस की वजह पूछे जाने पर: Default argument in c++मैं स्पष्ट रूप से निर्दिष्ट कर सकता हूं कि मैं कौन से तर्क पारित कर रहा हूं और कौन सा डिफ़ॉल्ट रहता है?

मैं इस जैसे एक समारोह है कहते हैं: void f(int p1=1, int p2=2, int p3=3, int p4=4);

और मैं केवल तर्क के कुछ का उपयोग कर इसे कॉल करना चाहते हैं - बाकी चूक हो जाएगा।

कुछ इस तरह काम करेंगे:

template<bool P1=true, bool P2=true, bool P3=true, bool P4=true> 
void f(int p1=1, int p2=2, int p3=3, int p4=4); 
// specialize: 
template<> 
void f<false, true, false, false>(int p1) { 
    f(1, p1); 
} 
template<> 
void f<false, true, true, false>(int p1, int p2) { 
    f(1, p1, p2); 
} 
// ... and so on. 
// Would need a specialization for each combination of arguments 
// which is very tedious and error-prone 

// Use: 
f<false, true, false, false>(5); // passes 5 as p2 argument 

लेकिन यह व्यावहारिक होने के लिए बहुत ज्यादा कोड की आवश्यकता है।

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

+0

आप वास्तव में क्या हासिल करना चाहते हैं? मुझे यह महसूस हो रहा है कि आप जो कुछ भी करने की कोशिश कर रहे हैं उसे सरल तरीके से किया जा सकता है। उपरोक्त कोड एक रखरखाव दुःस्वप्न की शुरुआत की तरह दिखता है। –

+0

@ एंडर्सके। यह निर्दिष्ट करने का एक तरीका है कि मैं किस तर्क का उपयोग करना चाहता हूं। मैं मानता हूं कि यह नहीं किया जाना चाहिए, लेकिन यदि संभव हो तो मैं अभी भी उत्सुक हूं। – Pubby

+1

क्या आपको वाकई इसकी आवश्यकता है? आपको तर्कों के तर्क (एन!) रूपों पर विचार करना होगा। 4! = 24 परिभाषाएं। यह सभी पैरामीटर –

उत्तर

11

नाम पैरामीटर मुहावरा का प्रयोग करें (→ FAQ link)।

Boost.Parameters पुस्तकालय (→ link) भी इस कार्य को हल है, लेकिन कोड शब्दाडंबर और बहुत कम स्पष्टता के लिए भुगतान कर सकते हैं। यह रचनाकारों को संभालने में भी कमी है। और इसके लिए बूस्ट लाइब्रेरी को निश्चित रूप से स्थापित करने की आवश्यकता है। ।

चीयर्स & hth,

+0

नामित पैरामीटर idiom केवल सेटटर कार्यों के समूह से सिंटैक्टिक रूप से अलग है। उत्तरार्द्ध आईएमएचओ अधिक प्राकृतिक है, क्योंकि जंजीर समारोह में गंध खराब होती है। दोनों दृष्टिकोणों में एक ही समस्या है, सीटीओ प्रारंभिकरण के विकल्प के रूप में इनिट प्रकार के कार्यों को बनाते हैं। –

+1

ध्यान रखें कि यदि आप टेम्पलेट कोड के लिए इसका उपयोग करते हैं तो पैरामीटर्स किसी भी कंपाइलर से कभी भी सबसे खराब त्रुटि संदेशों को उत्पन्न करेंगे। – pmr

7

Boost.Parameter लाइब्रेरी पर एक नज़र डालें।

यह सी ++ में पैरामीटर नामक लागू करता है। उदाहरण:

#include <boost/parameter/name.hpp> 
#include <boost/parameter/preprocessor.hpp> 
#include <iostream> 

//Define 
BOOST_PARAMETER_NAME(p1)  
BOOST_PARAMETER_NAME(p2) 
BOOST_PARAMETER_NAME(p3) 
BOOST_PARAMETER_NAME(p4) 

BOOST_PARAMETER_FUNCTION(
         (void), 
         f, 
         tag, 
         (optional    
          (p1, *, 1) 
          (p2, *, 2) 
          (p3, *, 3) 
          (p4, *, 4))) 
{ 
    std::cout << "p1: " << p1 
      << ", p2: " << p2 
      << ", p3: " << p3 
      << ", p4: " << p4 << "\n"; 
} 
//Use 
int main() 
{ 
    //Prints "p1: 1, p2: 5, p3: 3, p4: 4" 
    f(_p2=5); 
} 
+1

+1। यह दिलचस्प लग रहा है। लिंक के लिए धन्यवाद। :-) – Nawaz

+0

मुझे यह जवाब बहुत पसंद है, हालांकि यह थोड़ा अधिक है। – Pubby

+0

बूस्ट। पैरामीटर कार्य के लिए काफी अधिक है। –

2

यह वास्तव में एक जवाब नहीं है, लेकिन ...

C++ Template Metaprogramming दाऊद इब्राहीम और अलेक्सी Gurtovoy द्वारा में (! 2004 में प्रकाशित) लेखकों इस बारे में बात:

इस पुस्तक को लिखते समय, हमने नाम फ़ंक्शन पैरामीटर समर्थन के लिए उपयोग किए गए इंटरफ़ेस पर पुनर्विचार किया। एक छोटे से प्रयोग के साथ हम पता चला कि यह ओवरलोड काम ऑपरेटरों के साथ कीवर्ड वस्तुओं का उपयोग करके आदर्श वाक्य रचना प्रदान करने के लिए संभव है:

f(slew = .799, name = "z"); 

वे पर जाने के कहने के लिए:

हम नहीं कर रहे हैं इस नामित पैरामीटर लाइब्रेरी के कार्यान्वयन विवरण में शामिल होने के लिए; यह काफी सरल है कि हम का सुझाव देते हैं कि आप इसे व्यायाम के रूप में स्वयं लागू करने का प्रयास करें।

यह टेम्पलेट मेटाप्रोग्रामिंग और बूस्ट :: एमपीएल के संदर्भ में था। मुझे पूरा यकीन नहीं है कि कैसे उनके "straighforward" कार्यान्वयन डिफ़ॉल्ट पैरामीटर के साथ जैव होगा, लेकिन मुझे लगता है कि यह पारदर्शी होगा।

+0

यह वास्तव में बूस्ट के पीछे जादू का दिल है। पैरामीटर। मैंने इसे सफलतापूर्वक डीएसएल के लिए भी उपयोग किया है, यह वास्तव में साफ इंटरफेस बनाता है। –

+0

@MaththieuM। तो मुझे बस इतना करना है बूस्ट पढ़ना है। पैरामीटर हेडर इसे सीखने के लिए (काला?) जादू? जबकि मैं इसमें हूं, मुझे लगता है कि मैं * सभी * बूस्ट स्रोतों को पढ़ूंगा। तो मैं 70 साल की उम्र में एक अच्छा सी ++ प्रोग्रामर बन सकता हूं। :) –

+0

सचमुच, यह नहीं कह सकता कि मैं boost.parameters का उपयोग करना चाहता हूं, यह एक उत्सुक चीज है, लेकिन वास्तविक उपयोग में इलाज बीमारी से भी बदतर है। मैं या तो कोड पीढ़ी का उपयोग करता हूं या (यदि प्रदर्शन महत्वपूर्ण नहीं है) एक साधारण कुछ लाइन पार्सर और फ़ंक्शन को स्ट्रिंग की आपूर्ति करता है: 'f (" slew = .799, name = \ "z \" ");' –

4

हालांकि बूस्ट।पैरामीटर मनोरंजक है, यह (दुर्भाग्य से) ग्रस्त मुद्दों, जो बीच में टक्कर प्लेसहोल्डर (और विचित्र preprocessors/टेम्पलेट त्रुटियों डिबग करने वाले) के एक नंबर के लिए:

BOOST_PARAMETER_NAME(p1) 

_p1 प्लेसहोल्डर है कि आप तो बाद में उपयोग करने का निर्माण करेगा। यदि आपके पास एक ही प्लेसहोल्डर घोषित करने वाले दो अलग-अलग शीर्षलेख हैं, तो आपको एक संघर्ष मिलता है। मज़ा नहीं।

एक बहुत सरल (दोनों धारणात्मक और व्यावहारिक रूप से) जवाब है, Builder पैटर्न के आधार पर नहीं है कुछ हद तक नाम पैरामीटर मुहावरा है।

इसके बजाय इस तरह के एक समारोह को निर्दिष्ट करने के

:

void f(int a, int b, int c = 10, int d = 20); 

आप एक संरचना निर्दिष्ट करते हैं, जिस पर आप को पार कर जाएगी operator():

  • निर्माता (अनिवार्य तर्क के लिए पूछने के लिए प्रयोग किया जाता है सख्ती से नहीं में नामित पैरामीटर्स इडियॉम, लेकिन किसी ने भी नहीं कहा कि आपको इसे अंधाधुंध पालन करना होगा), और डिफ़ॉल्ट मान
  • प्रत्येक वैकल्पिक पैरामीटर को एक सेटटर
  • दिया गया है

आम तौर पर, यह चेनिंग के साथ संयुक्त है जिसमें सेटर्स वर्तमान ऑब्जेक्ट का संदर्भ लौटाते हैं ताकि कॉल को एक पंक्ति पर जंजीर किया जा सके।

class f { 
public: 
    // Take mandatory arguments, set default values 
    f(int a, int b): _a(a), _b(b), _c(10), _d(20) {} 

    // Define setters for optional arguments 
    // Remember the Chaining idiom 
    f& c(int v) { _c = v; return *this; } 
    f& d(int v) { _d = v; return *this; } 

    // Finally define the invocation function 
    void operator()() const; 

private: 
    int _a; 
    int _b; 
    int _c; 
    int _d; 
}; // class f 

मंगलाचरण है:

f(/*a=*/1, /*b=*/2).c(3)(); // the last() being to actually invoke the function 

मैं एक प्रकार operator() को पैरामीटर के रूप में अनिवार्य तर्क डाल देखा है, इस गुण के रूप में तर्क रखने से बचा जाता है लेकिन वाक्य रचना एक सा weirder है:

f().c(3)(/*a=*/1, /*b=*/2); 

एक बार संकलक ने सभी कन्स्ट्रक्टर और सेटर्स कॉल को रेखांकित किया है (यही कारण है कि उन्हें यहां परिभाषित किया गया है, जबकि operator() नहीं है), इसे res "नियमित" फ़ंक्शन आमंत्रण की तुलना में समान कुशल कोड में अल्ट।