2012-08-11 25 views
8

का उपयोग क्यों करना है मेरे पास स्कॉट मेयर्स के "प्रभावी सी ++" में आइटम 48 के बारे में एक त्वरित प्रश्न है। मैं बस नीचे दिए गए कोड किताब से नकल समझ में नहीं आता,सी ++ में टेम्पलेट, एनम

#include <iostream> 
    using namespace std; 

    template <unsigned n> 
    struct Factorial 
    { 
     enum { value=n*Factorial<n-1>::value }; 
    }; 

    template <> 
    struct Factorial<0> 
    { 
     enum { value=1}; 
    }; 

    int main() 
    { 
     cout<<Factorial<5>::value<<endl; 
     cout<<Factorial<10>::value<<endl; 
    } 

मैं टेम्पलेट प्रोग्रामिंग में enum उपयोग करने के लिए क्यों करते हैं? क्या ऐसा करने का कोई वैकल्पिक तरीका है? अग्रिम में सहायता के लिए धन्यवाद।

उत्तर

8

आप static const int भी इस्तेमाल कर सकते हैं:

template <unsigned n> 
struct Factorial 
{ 
    static const int value= n * Factorial<n-1>::value; 
}; 

template <> 
struct Factorial<0> 
{ 
    static const int value= 1; 
}; 

यह भी ठीक होना चाहिए। परिणाम दोनों मामलों में समान है।

या आप मौजूदा वर्ग टेम्पलेट का उपयोग कर सकता है, इस तरह के रूप में std::integral_constant (सी ++ 11 में केवल) के रूप में:

template <unsigned n> 
struct Factorial : std::integral_constant<int,n * Factorial<n-1>::value> {}; 

template <> 
struct Factorial<0> : std::integral_constant<int,1> {}; 
+0

यह वास्तव में सवाल का जवाब नहीं देता है, यही कारण है कि उन्होंने 'enum' का उपयोग किया। – Puppy

+0

@ नवाज स्पष्ट रूप से जवाब जानता है, लेकिन इसे स्पष्ट रूप से नहीं बताया। कुछ कंपाइलर्स में, 'स्थिर कॉन्स int' ** ** संकलित-समय स्थिर नहीं है ** क्योंकि पूर्व-सी ++ 11 मानक को संकलक को हल करने के लिए एक संपूर्ण प्रयास करने की आवश्यकता नहीं होती है। इसलिए, ** फ़ैक्टरियल 'में टेम्पलेट तर्क के रूप में ** इस तरह के' मान' का उपयोग करने का प्रयास कर रहा है, क्योंकि विफल हो सकता है क्योंकि संकलक ने यह निर्णय लिया होगा कि यह मान 'मान' को एक कॉन्स्टेक्सर नहीं बनाया गया हो। – rwong

1

आप static const int उपयोग कर सकते हैं के रूप में नवाज कहते हैं। मुझे लगता है कि स्कॉट मायर्स एक एनम का उपयोग करने का कारण यह है कि जब उन्होंने पुस्तक लिखी थी तो स्थैतिक कॉन्स पूर्णांक के इन-क्लास प्रारंभिकरण के लिए संकलक समर्थन थोड़ा सीमित था। तो एक enum एक सुरक्षित विकल्प था।

2

अधिक विशिष्ट होने के लिए, "enum hack" मौजूद है क्योंकि static const int के साथ ऐसा करने का अधिक सही तरीका उस समय के कई कंपाइलर्स द्वारा समर्थित नहीं था। यह आधुनिक कंपाइलर्स में अनावश्यक है।

4

मुझे लगता है कि अन्य उत्तरों वैकल्पिक दृष्टिकोण को अच्छी तरह से कवर करते हैं, लेकिन कोई भी समझाया नहीं गया है कि enum (या static const int) आवश्यक है।

#include <iostream> 

int Factorial(int n) 
{ 
    if (n == 0) 
     return 1; 
    else 
     return n * Factorial(n-1); 
} 

int main() 
{ 
    std::cout << Factorial(5) << std::endl; 
    std::cout << Factorial(10) << std::endl; 
} 

आप इसे आसानी से समझ में सक्षम होना चाहिए:

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

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

int main() 
{ 
    std::cout << 120 << std::endl; 
    std::cout << 3628800 << std::endl; 
} 

लेकिन आदेश है कि प्राप्त करने के लिए, आप 'चाल' संगणना प्रदर्शन में संकलक करने के लिए है। और ऐसा करने के लिए, आपको इसे कहीं भी परिणाम स्टोर करने की आवश्यकता है।

enum वास्तव में ऐसा करने के लिए में है। मैं यह समझाने की कोशिश करूंगा कि पर काम नहीं करेगा।

यदि आपने नियमित int का उपयोग करने का प्रयास किया है, तो यह काम नहीं करेगा क्योंकि int जैसे गैर-स्थिर सदस्य केवल तत्काल वस्तु में सार्थक हैं। और आप इसे इस तरह के मान को असाइन नहीं कर सकते हैं बल्कि इसके बजाय एक निर्माता में ऐसा करते हैं। एक सादा int काम नहीं करेगा।

आप कुछ है कि बजाय एक uninstantiated वर्ग पर सुलभ हो जाएगा की जरूरत है। आप static int आज़मा सकते हैं लेकिन यह अभी भी काम नहीं करता है।आप वास्तव में उन परिभाषाओं डालें, तो बाहर के लाइन, कोड संकलन है, लेकिन यह दो 0 रों में परिणाम होगा

c.cxx:6:14: error: non-const static data member must be initialized out of line 
       static int value=n*Factorial<n-1>::value ; 
         ^ ~~~~~~~~~~~~~~~~~~~~~~~ 

: clang आप समस्या का एक बहुत सरल विवरण देना होगा। ऐसा इसलिए है क्योंकि यह फ़ॉर्म प्रोग्राम की शुरुआत के लिए मानों की गणना में देरी करता है, और यह सही क्रम की गारंटी नहीं देता है। यह संभावना है कि गणना के पहले Factorial<n-1>::value एस प्राप्त किया गया था, और इस प्रकार 0 वापस कर दिया गया था। इसके अतिरिक्त, यह अभी भी हम वास्तव में नहीं चाहते हैं।

अंत में, यदि आप वहां static const int डालते हैं, तो यह अपेक्षा के अनुसार काम करेगा। ऐसा इसलिए है क्योंकि संकलन समय पर static const की गणना की जानी चाहिए, और यह वही है जो हम चाहते हैं। फिर से कोड टाइप करते हैं:

#include <iostream> 

template <unsigned n> 
struct Factorial 
{ 
    static const int value=n*Factorial<n-1>::value ; 
}; 

template <> 
struct Factorial<0> 
{ 
    static const int value=1; 
}; 

int main() 
{ 
    std::cout << Factorial<5>::value << std::endl; 
    std::cout << Factorial<10>::value << std::endl; 
} 

सबसे पहले आप का दृष्टांत Factorial<5>; static const int मजबूर करता है कि कंपाइलर को कंपाइलर समय पर इसकी मान गणना करनी होगी। प्रभावी रूप से, यह Factorial<4> प्रकार को तत्काल करता है जब इसे किसी अन्य मान की गणना करना पड़ता है। और यह तब तक जाता है जब तक यह Factorial<0> हिट नहीं करता है जहां मूल्य को तत्काल तत्काल बिना गणना की जा सकती है।

तो, यह वैकल्पिक तरीका और स्पष्टीकरण था। मुझे आशा है कि कोड को समझने में कम से कम थोड़ा सा मददगार होगा।

आप शुरुआत में पोस्ट किए गए रिकर्सिव फ़ंक्शन के प्रतिस्थापन के रूप में उस तरह के टेम्पलेट्स के बारे में सोच सकते हैं। तुम बस की जगह:

  • static const int value = ... साथ return x;,
  • t<x-1>::value साथ f(x-1),
  • और if (n == 0) विशेषज्ञता struct Factorial<0> साथ।

और enum खुद के लिए, किया गया था के रूप में यह पहले ही बताया है, यह उदाहरण में इस्तेमाल किया गया था static const int रूप में एक ही व्यवहार लागू करने के लिए। ऐसा इसलिए है क्योंकि सभी enum मान संकलन-समय पर ज्ञात होने की आवश्यकता है, इसलिए प्रभावी रूप से प्रत्येक अनुरोधित मान को संकलन-समय पर गणना की जानी चाहिए।

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