टेम्पलेट टेम्पलेट पैरामीटर के कुछ उपयोग क्या हैं?


238

मैंने नीति-आधारित वर्ग डिजाइन करने के लिए टेम्पलेट टेम्पलेट मापदंडों (जो टेम्पलेट के मापदंडों के रूप में टेम्पलेट लेते हैं) का उपयोग करके C ++ के कुछ उदाहरण देखे हैं। इस तकनीक के और क्या उपयोग हैं?


4
मैं दूसरी दिशा (FP, Haskell etc) से आया और इस पर उतरा: stackoverflow.com/questions/2565097/higher-kinded-types-with-c
एरिक कपलुन

जवाबों:


197

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

template <template<class> class H, class S>
void f(const H<S> &value) {
}

यहां, Hएक टेम्प्लेट है, लेकिन मैं चाहता था कि यह फ़ंक्शन सभी विशिष्टताओं से निपटे H

नोट : मैं कई वर्षों से c ++ प्रोग्रामिंग कर रहा हूं और केवल एक बार इसकी आवश्यकता है। मुझे लगता है कि यह शायद ही कभी आवश्यक विशेषता है (जब आपको इसकी आवश्यकता है!)।

मैं अच्छे उदाहरणों के बारे में सोचने की कोशिश कर रहा हूं, और ईमानदार होने के लिए, अधिकांश समय यह आवश्यक नहीं है, लेकिन आइए एक उदाहरण पर चर्चा करें। चलो बहाना है कि एक std::vector नहीं है typedef value_type

तो आप एक फ़ंक्शन कैसे लिखेंगे जो वैक्टर तत्वों के लिए सही प्रकार के चर बना सकते हैं? यह काम करेगा।

template <template<class, class> class V, class T, class A>
void f(V<T, A> &v) {
    // This can be "typename V<T, A>::value_type",
    // but we are pretending we don't have it

    T temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;
}

नोट : std::vectorदो टेम्प्लेट पैरामीटर हैं, टाइप करें, और आवंटन करें, इसलिए हमें दोनों को स्वीकार करना होगा। सौभाग्य से, टाइप कटौती के कारण, हमें सटीक प्रकार स्पष्ट रूप से लिखने की आवश्यकता नहीं होगी।

जो आप इस तरह का उपयोग कर सकते हैं:

f<std::vector, int>(v); // v is of type std::vector<int> using any allocator

या बेहतर अभी तक, हम सिर्फ उपयोग कर सकते हैं:

f(v); // everything is deduced, f can deal with a vector of any type!

अद्यतन : उदाहरण के लिए, जबकि यह काल्पनिक उदाहरण, c ++ 11 की शुरूआत के कारण एक अद्भुत उदाहरण नहीं है auto। अब उसी फंक्शन को लिखा जा सकता है:

template <class Cont>
void f(Cont &v) {

    auto temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;
}

जो है कि मैं इस प्रकार का कोड कैसे लिखना चाहूंगा।


1
यदि लाइब्रेरी के उपयोगकर्ता द्वारा परिभाषित किया गया फ़ंक्शन f है, तो यह बदसूरत है कि उपयोगकर्ता को एक तर्क के रूप में std :: एलोकेटर <T> पास करना होगा। मुझे उम्मीद है कि एसटीडी के बिना संस्करण :: आवंटन तर्क ने एसटीडी के डिफ़ॉल्ट पैरामीटर का उपयोग करके काम किया है :: वेक्टर। क्या इस wrt C ++ 0x पर कोई अपडेट है?
अमित

ठीक है, आपको आवंटन प्रदान करने की आवश्यकता नहीं है। क्या महत्वपूर्ण है कि टेम्पलेट टेम्पलेट पैरामीटर को सही संख्या में तर्कों से परिभाषित किया गया था। लेकिन फ़ंक्शन को परवाह नहीं करनी चाहिए कि उनके "प्रकार" या अर्थ क्या हैं, निम्नलिखित C ++ 98 में अच्छी तरह से काम करता है:template<template<class, class> class C, class T, class U> void f(C<T, U> &v)
pfalcon

मुझे आश्चर्य है कि तात्कालिकता क्यों है f<vector,int>और क्या नहीं f<vector<int>>
बोब्बोबो

2
@bobobobo इन दोनों का मतलब अलग-अलग है। f<vector,int>साधन f<ATemplate,AType>, f<vector<int>>साधनf<AType>
user362515

@ फ़ेडर्रस: (बहुत बाद में ...) अच्छे अंक, आवंटनकर्ता को सामान्य बनाने के लिए उदाहरण में सुधार और उदाहरण अधिक स्पष्ट :-)
इवान टेरान

163

वास्तव में, टेम्पलेट टेम्पलेट मापदंडों के लिए usecase बल्कि स्पष्ट है। एक बार जब आप सीख लेते हैं कि C ++ stdlib में मानक कंटेनर प्रकारों के लिए स्ट्रीम आउटपुट ऑपरेटरों को परिभाषित नहीं करने का छेद है, तो आप कुछ इस तरह से लिखना चाहेंगे:

template<typename T>
static inline std::ostream& operator<<(std::ostream& out, std::list<T> const& v)
{
    out << '[';
    if (!v.empty()) {
        for (typename std::list<T>::const_iterator i = v.begin(); ;) {
            out << *i;
            if (++i == v.end())
                break;
            out << ", ";
        }
    }
    out << ']';
    return out;
}

फिर आप यह पता लगाएंगे कि वेक्टर के लिए कोड सिर्फ एक ही है, फॉरवर्ड_लिस्ट एक ही है, वास्तव में, यहां तक ​​कि मानचित्र प्रकारों की भीड़ के लिए यह अभी भी केवल एक ही है। उन टेम्प्लेट क्लासेस में मेटा-इंटरफ़ेस / प्रोटोकॉल को छोड़कर कुछ भी सामान्य नहीं है, और टेम्प्लेट टेम्पलेट पैरामीटर का उपयोग करके उन सभी में समानता को पकड़ने की अनुमति मिलती है। हालांकि एक टेम्प्लेट लिखने के लिए आगे बढ़ने से पहले, यह याद रखने के लिए एक संदर्भ की जांच करने के लायक है कि अनुक्रम कंटेनर 2 टेम्पलेट तर्क स्वीकार करते हैं - मूल्य प्रकार और आवंटन के लिए। जब आवंटनकर्ता चूक कर रहा है, तब भी हमें अपने टेम्पलेट ऑपरेटर में इसके अस्तित्व के लिए खाता होना चाहिए <<:

template<template <typename, typename> class Container, class V, class A>
std::ostream& operator<<(std::ostream& out, Container<V, A> const& v)
...

वोइला, जो मानक प्रोटोकॉल का पालन करने वाले सभी वर्तमान और भविष्य के अनुक्रम कंटेनरों के लिए स्वचालित रूप से काम करेगा। मिश्रण में मानचित्र जोड़ने के लिए, यह ध्यान में रखना चाहिए कि वे 4 टेम्प्लेट पैराम को स्वीकार करते हैं, इसलिए हमें ऑपरेटर के एक और संस्करण की आवश्यकता होगी << 4-एर्ग टेम्पलेट टेम्प्लेट परम के साथ। हम यह भी देखेंगे कि एसटीडी: जोड़ी को 2-arg ऑपरेटर के साथ प्रदान करने की कोशिश की जाती है << अनुक्रम प्रकारों के लिए जिसे हमने पहले परिभाषित किया था, इसलिए हम सिर्फ std :: pair के लिए एक विशेषज्ञता प्रदान करेंगे।

Btw, C + 11 के साथ जो वैरेडिक टेम्प्लेट की अनुमति देता है (और इस तरह से वैरेडिक टेम्प्लेट टेम्पलेट को अनुमति देता है), उन सभी पर शासन करने के लिए एकल ऑपरेटर << होना संभव होगा। उदाहरण के लिए:

#include <iostream>
#include <vector>
#include <deque>
#include <list>

template<typename T, template<class,class...> class C, class... Args>
std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs)
{
    os << __PRETTY_FUNCTION__ << '\n';
    for (auto const& obj : objs)
        os << obj << ' ';
    return os;
}

int main()
{
    std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
    std::cout << vf << '\n';

    std::list<char> lc { 'a', 'b', 'c', 'd' };
    std::cout << lc << '\n';

    std::deque<int> di { 1, 2, 3, 4 };
    std::cout << di << '\n';

    return 0;
}

उत्पादन

std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = float, C = vector, Args = <std::__1::allocator<float>>]
1.1 2.2 3.3 4.4 
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = char, C = list, Args = <std::__1::allocator<char>>]
a b c d 
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = int, C = deque, Args = <std::__1::allocator<int>>]
1 2 3 4 

9
यह टेम्पलेट टेम्पलेट मापदंडों का एक ऐसा मधुर उदाहरण है, क्योंकि यह एक ऐसा मामला दिखाता है जिससे हर किसी को निपटना पड़ा है।
रावेन वाटर

3
यह C ++ टेम्प्लेट में मेरे लिए सबसे जागृत उत्तर है। @HozCraig आपको टेम्पलेट विस्तार विवरण कैसे मिले?
अरुण

3
@ अरुण जीसीसी एक मैक्रो का समर्थन करता है __PRETTY_FUNCTION__, जो अन्य बातों के अलावा, सादा पाठ में टेम्पलेट पैरामीटर विवरण की रिपोर्ट करता है। क्लैंग यह भी करता है। एक सबसे आसान सुविधा कभी-कभी (जैसा कि आप देख सकते हैं)।
व्हाट्सक्रैग

20
यहाँ टेम्पलेट टेम्पलेट पैरामीटर वास्तव में कोई मूल्य नहीं जोड़ रहा है। आप किसी वर्ग टेम्पलेट के किसी भी दिए गए उदाहरण के साथ-साथ नियमित टेम्पलेट पैरामीटर का उपयोग कर सकते हैं।
डेविड स्टोन

9
मुझे डेविड स्टोन से सहमत होना होगा। यहाँ टेम्पलेट टेम्पलेट पैरामीटर का कोई मतलब नहीं है। यह एक सादा टेम्पलेट बनाने के लिए बहुत सरल और समान रूप से प्रभावी होगा (टेम्पलेट <टाइपनाम कंटेनर>)। मुझे पता है कि यह पोस्ट काफी पुरानी है, इसलिए मैं केवल उन लोगों के लिए अपने 2 सेंट जोड़ रहा हूं, जो इस उत्तर को भरते हैं, जो टेम्प्लेट के बारे में जानकारी की तलाश में हैं।
जिम वर्गो

67

आंद्रेई अलेक्जेंड्रक द्वारा 'मॉडर्न सी ++ डिज़ाइन - जेनेरिक प्रोग्रामिंग एंड डिज़ाइन पैटर्न एप्लाइड' से लिया गया एक सरल उदाहरण यहाँ दिया गया है :

वह पॉलिसी पैटर्न को लागू करने के लिए टेम्प्लेट टेम्पलेट मापदंडों के साथ एक वर्ग का उपयोग करता है:

// Library code
template <template <class> class CreationPolicy>
class WidgetManager : public CreationPolicy<Widget>
{
   ...
};

वे बताते हैं: आमतौर पर, मेजबान वर्ग पहले से ही जानता है, या आसानी से कटौती कर सकता है, नीति वर्ग का टेम्पलेट तर्क। ऊपर के उदाहरण में, WidgetManager हमेशा Widget की वस्तुओं का प्रबंधन करता है, इसलिए उपयोगकर्ता को CreatPolicy की तात्कालिकता में फिर से विजेट को निर्दिष्ट करने की आवश्यकता होती है, अनावश्यक और संभावित रूप से खतरनाक है। इस मामले में, लाइब्रेरी कोड नीतियों को निर्दिष्ट करने के लिए टेम्पलेट टेम्पलेट मापदंडों का उपयोग कर सकता है।

इसका प्रभाव यह है कि क्लाइंट कोड 'विजेटस्ट्रीमर' का अधिक सुरुचिपूर्ण तरीके से उपयोग कर सकता है:

typedef WidgetManager<MyCreationPolicy> MyWidgetMgr;

इसके बजाय अधिक बोझिल, और त्रुटि प्रवण तरीका है कि एक परिभाषा टेम्पलेट टेम्पलेट तर्क की कमी की आवश्यकता होगी:

typedef WidgetManager< MyCreationPolicy<Widget> > MyWidgetMgr;

1
प्रश्न विशेष रूप से नीति पैटर्न के अलावा अन्य उदाहरणों के लिए अनुरोध किया गया है।
user2913094

मैं इस किताब से बिल्कुल इस सवाल पर आया था। एक योग्य नोट यह है कि टेंप्लेटिस्ट चैप्टर और टेंपेलिस्ट चैप्टर के साथ क्लास जनरेशन में टेम्प्लेट टेम्पलेट पैरामीटर भी दिखाई देते हैं ।
विक्टर

18

यहाँ मेरा CUDA संवेदी तंत्रिका नेटवर्क लाइब्रेरी से एक और व्यावहारिक उदाहरण है । मेरे पास निम्न वर्ग टेम्पलेट है:

template <class T> class Tensor

जो वास्तव में एन-आयामी मेट्रिसेस हेरफेर को लागू करता है। चाइल्ड क्लास टेम्प्लेट भी है:

template <class T> class TensorGPU : public Tensor<T>

जो एक ही कार्यक्षमता को लागू करता है, लेकिन GPU में। दोनों टेम्पलेट सभी बुनियादी प्रकारों के साथ काम कर सकते हैं, जैसे फ्लोट, डबल, इंट, आदि और मेरे पास एक क्लास टेम्पलेट (सरलीकृत) भी है:

template <template <class> class TT, class T> class CLayerT: public Layer<TT<T> >
{
    TT<T> weights;
    TT<T> inputs;
    TT<int> connection_matrix;
}

यहाँ टेम्पलेट टेम्पलेट सिंटैक्स होने का कारण यह है कि मैं कक्षा के कार्यान्वयन की घोषणा कर सकता हूं

class CLayerCuda: public CLayerT<TensorGPU, float>

जिसमें वेट और टाइप के दोनों तरह के फ्लोट्स होंगे और GPU पर, लेकिन कनेक्शन_मैटिक्स हमेशा int होगा, या तो CPU पर (TT = Tensor को निर्दिष्ट करके) या GPU पर (TT = TensorGPU को निर्दिष्ट करके)।


क्या आप कुछ के साथ T की कटौती को बाध्य कर सकते हैं जैसे: "टेम्पलेट <वर्ग T, टेम्पलेट <T> TT> CLayerT" और "वर्ग CLayerCuda: public CLayerT <TensorGPU <float >>"? मामले में आपको टीटी की आवश्यकता नहीं थी <otherT>
NicoBerrogorry

कभी नहीं: टेम्पलेट <टेम्पलेट <वर्ग T> वर्ग U> वर्ग B1 {}; से ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/... एक त्वरित गूगल खोज से
NicoBerrogorry

12

कहते हैं कि आप बाल टेम्पलेट्स के एक सेट के लिए "इंटरफ़ेस" प्रदान करने के लिए CRTP का उपयोग कर रहे हैं; और माता-पिता और बच्चा दोनों अन्य टेम्पलेट तर्क में पैरामीट्रिक हैं:

template <typename DERIVED, typename VALUE> class interface {
    void do_something(VALUE v) {
        static_cast<DERIVED*>(this)->do_something(v);
    }
};

template <typename VALUE> class derived : public interface<derived, VALUE> {
    void do_something(VALUE v) { ... }
};

typedef interface<derived<int>, int> derived_t;

'Int' के दोहराव पर ध्यान दें, जो वास्तव में एक ही प्रकार का पैरामीटर दोनों टेम्पलेट्स के लिए निर्दिष्ट है। इस दोहराव से बचने के लिए आप DERIVED के लिए एक टेम्प्लेट टेम्पलेट का उपयोग कर सकते हैं:

template <template <typename> class DERIVED, typename VALUE> class interface {
    void do_something(VALUE v) {
        static_cast<DERIVED<VALUE>*>(this)->do_something(v);
    }
};

template <typename VALUE> class derived : public interface<derived, VALUE> {
    void do_something(VALUE v) { ... }
};

typedef interface<derived, int> derived_t;

ध्यान दें कि आप व्युत्पन्न टेम्पलेट को अन्य टेम्पलेट पैरामीटर (ओं) को सीधे प्रदान कर रहे हैं ; "इंटरफ़ेस" अभी भी उन्हें प्राप्त करता है।

यह आपको "इंटरफ़ेस" में टाइपपैड बनाने की सुविधा भी देता है जो कि प्रकार के मापदंडों पर निर्भर करता है, जो व्युत्पन्न टेम्पलेट से सुलभ होगा।

उपर्युक्त टाइपफाइफ़ काम नहीं करता है क्योंकि आप एक अनिर्दिष्ट टेम्पलेट में टाइप नहीं कर सकते हैं। हालाँकि, यह काम करता है (और C ++ 11 में टेम्पलेट टाइपडिफ के लिए मूल समर्थन है):

template <typename VALUE>
struct derived_interface_type {
    typedef typename interface<derived, VALUE> type;
};

typedef typename derived_interface_type<int>::type derived_t;

दुर्भाग्यवश, व्युत्पन्न टेम्पलेट के प्रत्येक तात्कालिकता के लिए आपको एक व्युत्पन्न_हृदय_प्रकार की आवश्यकता है, जब तक कि एक और चाल नहीं है जो मैंने अभी तक नहीं सीखा है।


मुझे कुछ कोड के लिए इस सटीक समाधान की आवश्यकता थी (धन्यवाद!)। यद्यपि यह काम करता है, मुझे समझ में नहीं आता है कि टेम्प्लेट क्लास derivedका उपयोग इसके टेम्प्लेट के तर्कों के बिना कैसे किया जा सकता है, अर्थात लाइनtypedef typename interface<derived, VALUE> type;
कार्लटन

@ कार्लटन यह मूल रूप से काम करता है क्योंकि संबंधित टेम्पलेट पैरामीटर को भरे जाने को ए के रूप में परिभाषित किया गया है template <typename>। एक मायने में आप '' मेटाटाइप '' के रूप में टेम्प्लेट मापदंडों के बारे में सोच सकते हैं; एक टेम्पलेट पैरामीटर के लिए सामान्य मेटाटाइप है, typenameजिसका अर्थ है कि इसे एक नियमित प्रकार से भरना होगा; templatemetatype साधन इसकी आवश्यकता है एक टेम्पलेट के लिए एक संदर्भ के साथ भरे जाने हैं। derivedएक टेम्पलेट को परिभाषित करता है जो एक typenameमेटाटाइप्ड पैरामीटर को स्वीकार करता है , इसलिए यह बिल को फिट करता है और यहां संदर्भित किया जा सकता है। सही बात?
मार्क मैककेना

C ++ 11 अभी भी अभी तक typedef। इसके अलावा, आप DERIVED प्रकार में intएक मानक निर्माण का उपयोग करके अपने पहले उदाहरण में डुप्लिकेट से बच सकते हैं value_type
रुबेंव

यह उत्तर वास्तव में C ++ 11 को लक्षित नहीं करता है; मैंने C ++ 11 को केवल यह कहने के लिए संदर्भित किया कि आप typedefब्लॉक 2 से समस्या के आसपास पहुंच सकते हैं । लेकिन बिंदु 2 वैध है मुझे लगता है ... हाँ, यह शायद एक ही काम करने का एक सरल तरीका होगा।
मार्क मैकेना

7

यह वही है जो मैं भाग गया:

template<class A>
class B
{
  A& a;
};

template<class B>
class A
{
  B b;
};

class AInstance : A<B<A<B<A<B<A<B<... (oh oh)>>>>>>>>
{

};

इसे हल किया जा सकता है:

template<class A>
class B
{
  A& a;
};

template< template<class> class B>
class A
{
  B<A> b;
};

class AInstance : A<B> //happy
{

};

या (काम कोड):

template<class A>
class B
{
public:
    A* a;
    int GetInt() { return a->dummy; }
};

template< template<class> class B>
class A
{
public:
    A() : dummy(3) { b.a = this; }
    B<A> b;
    int dummy;
};

class AInstance : public A<B> //happy
{
public:
    void Print() { std::cout << b.GetInt(); }
};

int main()
{
    std::cout << "hello";
    AInstance test;
    test.Print();
}

4

Pfalcon द्वारा प्रदान किए जाने वाले वैरेडिक टेम्प्लेट के साथ समाधान में, मुझे वास्तव में stad :: मानचित्र के लिए ओस्ट्रीम ऑपरेटर को समझना मुश्किल हो गया, जो कि वैरेडिक विशेषज्ञता के लालची स्वभाव के कारण है। यहाँ एक छोटा सा संशोधन है जो मेरे लिए काम कर रहा है:

#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <map>

namespace containerdisplay
{
  template<typename T, template<class,class...> class C, class... Args>
  std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs)
  {
    std::cout << __PRETTY_FUNCTION__ << '\n';
    for (auto const& obj : objs)
      os << obj << ' ';
    return os;
  }  
}

template< typename K, typename V>
std::ostream& operator << ( std::ostream& os, 
                const std::map< K, V > & objs )
{  

  std::cout << __PRETTY_FUNCTION__ << '\n';
  for( auto& obj : objs )
  {    
    os << obj.first << ": " << obj.second << std::endl;
  }

  return os;
}


int main()
{

  {
    using namespace containerdisplay;
    std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
    std::cout << vf << '\n';

    std::list<char> lc { 'a', 'b', 'c', 'd' };
    std::cout << lc << '\n';

    std::deque<int> di { 1, 2, 3, 4 };
    std::cout << di << '\n';
  }

  std::map< std::string, std::string > m1 
  {
      { "foo", "bar" },
      { "baz", "boo" }
  };

  std::cout << m1 << std::endl;

    return 0;
}

2

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

#include <vector>

template <class T> class Alloc final { /*...*/ };

template <template <class T> class allocator=Alloc> class MyClass final {
  public:
    std::vector<short,allocator<short>> field0;
    std::vector<float,allocator<float>> field1;
};

2

यह आपके कोड की पठनीयता में सुधार करता है, अतिरिक्त प्रकार की सुरक्षा प्रदान करता है और कुछ संकलक प्रयासों को बचाता है।

मान लें कि आप किसी कंटेनर के प्रत्येक तत्व को प्रिंट करना चाहते हैं, तो आप टेम्पलेट कोड पैरामीटर के बिना निम्नलिखित कोड का उपयोग कर सकते हैं

template <typename T> void print_container(const T& c)
{
    for (const auto& v : c)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}

या टेम्पलेट टेम्पलेट पैरामीटर के साथ

template< template<typename, typename> class ContainerType, typename ValueType, typename AllocType>
void print_container(const ContainerType<ValueType, AllocType>& c)
{
    for (const auto& v : c)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}

मान लें कि आप पूर्णांक में कहते हैं print_container(3)। पूर्व मामले के लिए, टेम्पलेट को कंपाइलर द्वारा त्वरित किया जाएगा जो cलूप के लिए उपयोग के बारे में शिकायत करेगा , बाद वाला टेम्पलेट को बिल्कुल भी नहीं हटाएगा क्योंकि कोई मिलान प्रकार नहीं मिल सकता है।

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


1

मैं इसका उपयोग संस्करण प्रकारों के लिए करता हूं।

यदि आपके पास टेम्पलेट के माध्यम से एक प्रकार का संस्करण है MyType<version>, जैसे , आप एक फ़ंक्शन लिख सकते हैं जिसमें आप संस्करण संख्या पर कब्जा कर सकते हैं:

template<template<uint8_t> T, uint8_t Version>
Foo(const T<Version>& obj)
{
    assert(Version > 2 && "Versions older than 2 are no longer handled");
    ...
    switch (Version)
    {
    ...
    }
}

इसलिए आप प्रत्येक प्रकार के लिए एक अधिभार होने के बजाय पारित किए जा रहे प्रकार के आधार पर अलग-अलग चीजें कर सकते हैं। आपके पास रूपांतरण कार्य भी हो सकते MyType<Version>हैं MyType<Version+1>, जो सामान्य तरीके से लेते हैं और वापस आते हैं , और यहां तक ​​कि उन्हें एक ToNewest()फ़ंक्शन के लिए फिर से तैयार करते हैं जो किसी भी पुराने संस्करण से एक प्रकार का नवीनतम संस्करण लौटाता है (लॉग के लिए बहुत उपयोगी है जो थोड़ी देर पहले संग्रहीत किया गया हो सकता है) लेकिन आज के नवीनतम उपकरण के साथ संसाधित होने की आवश्यकता है)।

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