टेम्पलेट <अहस्ताक्षरित int N> का क्या अर्थ है?


121

टेम्प्लेट की घोषणा करते समय, मुझे इस तरह के कोड का उपयोग करने के लिए उपयोग किया जाता है:

template <class T>

लेकिन इस सवाल में , उन्होंने इस्तेमाल किया:

template <unsigned int N>

मैंने जाँच की कि यह संकलित है। लेकिन इसका मतलब क्या है? क्या यह एक गैर-प्रकार का पैरामीटर है? और यदि हां, तो किसी भी प्रकार के पैरामीटर के बिना हमारे पास एक टेम्पलेट कैसे हो सकता है?

जवाबों:


148

एक प्रकार के बजाय पूर्णांक पर एक वर्ग को टेम्पलेट देना पूरी तरह से संभव है। हम एक वैरिएबल को टेम्पर्ड वैल्यू असाइन कर सकते हैं, या अन्यथा इसे किसी अन्य पूर्णांक शाब्दिक के साथ जोड़ सकते हैं।

unsigned int x = N;

वास्तव में, हम एल्गोरिदम बना सकते हैं जो संकलन के समय ( विकिपीडिया से ) का मूल्यांकन करते हैं :

template <int N>
struct Factorial 
{
     enum { value = N * Factorial<N - 1>::value };
};

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

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

11
आप static constexpr intअपने बजाय टाइप का उपयोग भी कर सकते हैं enum। तो Factorial<0>टेम्पलेट होगा static constexpr int value = 1, और template <int N> struct Factorialहो सकता हैstatic constexpr int value = N * Factorial<N - 1>::value;
bobobobo

@bobobobo को C ++ 11 से पहले इसका उत्तर दिया गया था constexpr
जस्टिन मीनर्स

154

हां, यह एक गैर-प्रकार का पैरामीटर है। आपके पास कई प्रकार के टेम्पलेट पैरामीटर हो सकते हैं

  • पैरामीटर्स टाइप करें।
    • प्रकार
    • टेम्प्लेट (केवल कक्षाएं और अन्य नाम टेम्पलेट, कोई फ़ंक्शन या चर टेम्पलेट)
  • नॉन-टाइप पैरामीटर्स
    • संकेत
    • संदर्भ
    • एकात्म भाव

आपके पास जो है वह अंतिम प्रकार का है। यह एक संकलन समय स्थिर (तथाकथित स्थिर अभिव्यक्ति) है और प्रकार पूर्णांक या गणना है। मानक में इसे देखने के बाद, मुझे कक्षा के खाकों को अनुभागों में ऊपर ले जाना पड़ा - भले ही वे टेम्पलेट प्रकार न हों। लेकिन फिर भी उन प्रकारों का वर्णन करने के उद्देश्य से उन्हें टाइप-पैरामीटर कहा जाता है। आपके पास पॉइंटर्स (और सदस्य पॉइंटर्स) और ऑब्जेक्ट्स / फ़ंक्शंस के संदर्भ भी हो सकते हैं, जिनमें बाहरी लिंकेज हैं (जिन्हें अन्य ऑब्जेक्ट फ़ाइलों से जोड़ा जा सकता है और जिनका पता पूरे प्रोग्राम में अद्वितीय है)। उदाहरण:

टेम्पलेट प्रकार पैरामीटर:

template<typename T>
struct Container {
    T t;
};

// pass type "long" as argument.
Container<long> test;

टेम्प्लेट पूर्णांक पैरामीटर:

template<unsigned int S>
struct Vector {
    unsigned char bytes[S];
};

// pass 3 as argument.
Vector<3> test;

टेम्प्लेट पॉइंटर पैरामीटर (किसी फ़ंक्शन को पॉइंटर पास करना)

template<void (*F)()>
struct FunctionWrapper {
    static void call_it() { F(); }
};

// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;

टेम्प्लेट संदर्भ पैरामीटर (पूर्णांक पास करना)

template<int &A>
struct SillyExample {
    static void do_it() { A = 10; }
};

// pass flag as argument
int flag;
SillyExample<flag> test;

टेम्पलेट टेम्पलेट पैरामीटर।

template<template<typename T> class AllocatePolicy>
struct Pool {
    void allocate(size_t n) {
        int *p = AllocatePolicy<int>::allocate(n);
    }
};

// pass the template "allocator" as argument. 
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;

बिना किसी पैरामीटर के एक टेम्पलेट संभव नहीं है। लेकिन बिना किसी स्पष्ट तर्क के एक टेम्पलेट संभव है - इसमें डिफ़ॉल्ट तर्क हैं:

template<unsigned int SIZE = 3>
struct Vector {
    unsigned char buffer[SIZE];
};

Vector<> test;

सामान्यतया, template<>एक स्पष्ट टेम्पलेट विशेषज्ञता को चिह्नित करने के लिए आरक्षित है, मापदंडों के बिना एक टेम्पलेट के बजाय:

template<>
struct Vector<3> {
    // alternative definition for SIZE == 3
};

जोहान्स, "प्रकार" के तहत दर्ज किए गए टेम्पलेट हैं? मैंने सोचा कि वे किस प्रकार से बनाए जा सकते हैं, लेकिन स्वयं प्रकार नहीं?
sbi

@ एसबीआई स्पष्टीकरण देखें: "इसे मानक में देखने के बाद, मुझे क्लास के टेम्प्लेट्स को टाइप सेक्शन में ले जाना पड़ा - भले ही टाइप्स टाइप न हों। लेकिन उन्हें उन प्रकारों का वर्णन करने के उद्देश्य से टाइप-पैरामीटर्स कहा जाता है। "। 14.1 / 2 को फुटनोट 126 ऐसा कहता है। यह केवल गैर-प्रकार के मापदंडों को बनाने के लिए बनाया गया एक वर्गीकरण है जो एक मूल्य / संदर्भ और प्रकार-पैरामीटर घोषित करता है कुछ प्रकार का नाम या टेम्पलेट का नाम घोषित करता है।
जोहान्स शहाब -

@ जोहान्सचैब-लिटब तो वहाँ टेम्पलेट के साथ टाइप करने का कोई तरीका नहीं है std :: string? जैसे टेम्प्लेट <std :: string S> क्लास में कुछ स्टैटिक काउंटर के साथ हर अलग स्ट्रिंग के लिए यूनिक आईडी बनाने के लिए? हैशिंग स्ट्रिंग टू इंट दुर्भाग्यपूर्ण ही सही तरीका होगा?
9

1
मुझे टेम्पलेट क्लास के सदस्य ऑब्जेक्ट्स के साथ पूरा किया गया यह उत्तर देखना अच्छा लगेगा, अर्थात टेम्प्लेट <टाइपनेम का नाम, टाइपनेम का नाम, टाइपनाम का पी 1, टाइप का नाम P2> स्ट्रक्चर मिस्ट्रिक्ट <R (C :: *) (P1, P2)>
जॉनी पॉलिंग

कोड का टुकड़ा SillyExampleजीसीसी 4.8.4 द्वारा संकलित नहीं किया जा सकता है। पहली त्रुटि है the value of ‘flag’ is not usable in a constant expression। अन्य त्रुटियां भी हैं
HEKTO

17

आप अपनी कक्षा को 'अहस्ताक्षरित int' पर आधारित करते हैं।

उदाहरण:

template <unsigned int N>
class MyArray
{
    public:
    private:
        double    data[N]; // Use N as the size of the array
};

int main()
{
    MyArray<2>     a1;
    MyArray<2>     a2;

    MyArray<4>     b1;

    a1 = a2;  // OK The arrays are the same size.
    a1 = b1;  // FAIL because the size of the array is part of the
              //      template and thus the type, a1 and b1 are different types.
              //      Thus this is a COMPILE time failure.
 }

15

एक टेम्पलेट वर्ग एक मैक्रो की तरह है, केवल एक पूरी बहुत कम बुराई है।

एक टेम्पलेट को मैक्रो के रूप में सोचें। टेम्प्लेट के मापदंडों को एक वर्ग (या फ़ंक्शन) परिभाषा में प्रतिस्थापित किया जाता है, जब आप टेम्पलेट का उपयोग करके एक वर्ग (या फ़ंक्शन) को परिभाषित करते हैं।

अंतर यह है कि पैरामीटर में "प्रकार" होते हैं और पारित किए गए मानों को संकलन के दौरान चेक किया जाता है, जैसे कार्यों के लिए पैरामीटर। वैध प्रकार आपके नियमित C ++ प्रकार हैं, जैसे int और char। जब आप टेम्प्लेट क्लास को तात्कालिक करते हैं, तो आप अपने द्वारा निर्दिष्ट प्रकार का एक मान पास करते हैं, और टेम्प्लेट क्लास परिभाषा की एक नई प्रति में यह मान प्रतिस्थापित किया जाता है, जहां पैरामीटर नाम मूल परिभाषा में था। एकदम स्थूल की तरह।

आप मापदंडों के लिए " class" या " typename" प्रकारों का उपयोग कर सकते हैं (वे वास्तव में समान हैं)। इनमें से किसी एक प्रकार के पैरामीटर के साथ, आप एक मान के बजाय एक प्रकार का नाम दे सकते हैं। पहले की तरह, हर जगह पैरामीटर नाम टेम्प्लेट क्लास की परिभाषा में था, जैसे ही आप एक नया उदाहरण बनाते हैं, आप जिस भी प्रकार से गुजरते हैं। यह टेम्पलेट क्लास के लिए सबसे आम उपयोग है; C ++ टेम्प्लेट के बारे में कुछ भी जानने वाला हर व्यक्ति जानता है कि यह कैसे करना है।

इस टेम्प्लेट क्लास उदाहरण कोड पर विचार करें:

#include <cstdio>
template <int I>
class foo
{
  void print()
  {
    printf("%i", I);
  }
};

int main()
{
  foo<26> f;
  f.print();
  return 0;
}

यह कार्यात्मक रूप से इस मैक्रो-उपयोग कोड के समान है:

#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
  void print() \
  { \
    printf("%i", I); \
  } \
};

MAKE_A_FOO(26)

int main()
{
  foo_26 f;
  f.print();
  return 0;
}

बेशक, टेम्पलेट संस्करण एक अरब गुना अधिक सुरक्षित और अधिक लचीला है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.