2009-07-31 15 views
21

मैं वास्तविक दुनिया परिदृश्यों के लिए टेम्पलेट प्रोग्रामिंग (और भविष्य के बिंदु, टेम्पलेट मेटाप्रोग्रामिंग) पर अपने सिर को प्राप्त करने की कोशिश कर रहा हूं। मुझे लगता है कि एक समस्या यह है कि सी ++ टेम्पलेट्स और पॉलिमॉर्फिज्म हमेशा जिस तरह से मैं चाहता हूं उसे एक साथ नहीं खेलता।ओओ polymorphism के स्थान पर टेम्पलेट polymorphism का उपयोग किया जा सकता है?

मेरा प्रश्न यह है कि जिस तरह से मैं टेम्पलेट प्रोग्रामिंग लागू करने की कोशिश कर रहा हूं वह अनुचित है (और मुझे सादे पुराने ओओपी का उपयोग करना चाहिए) या यदि मैं अभी भी ओओपी मानसिकता में फंस गया हूं।

इस विशेष मामले में, मैं रणनीति-पैटर्न का उपयोग कर समस्या हल करने का प्रयास कर रहा हूं। मैं उस समस्या में भागता रहता हूं जहां मैं कुछ ऐसा करना चाहता हूं जो पॉलिमॉर्फिक व्यवहार करता है जो टेम्पलेट्स का समर्थन नहीं करता है।

OOP कोड का उपयोग कर रचना:

class Interpolator { 
    public: 
    Interpolator(ICacheStrategy* const c, IDataSource* const d); 
    Value GetValue(const double); 
} 

void main(...) { 
    Interpolator* i; 
    if(param==1) 
     i = new Interpolator(new InMemoryStrategy(...), new TextFileDataSource(...)); 
    else if(param==2) 
     i = new Interpolator(new InMemoryStrategy(...), new OdbcDataSource(...)); 
    else if(param==3) 
     i = new Interpolator(new NoCachingStrategy(...), new RestDataSource(...)); 

    while(run) { 
     double input = WaitForRequest(); 
     SendRequest(i->GetValue(input)); 
    } 
} 

संभावित खाका संस्करण:

class Interpolator<class TCacheStrategy, class TDataSource> { 
    public: 
    Interpolator(); 
    Value GetValue(const double);    //may not be the best way but 
    void ConfigCache(const& ConfigObject);  //just to illustrate Cache/DS   
    void ConfigDataSource(const& ConfigObject); //need to configured 

} 

//Possible way of doing main? 
void main(...) { 
    if(param==1) 
     DoIt(Interpolator<InMemoryStrategy,TextFileDataSource>(),c,d); 
    else if(param==2) 
     DoIt(Interpolator<InMemoryStrategy,OdbcDataSource>(),c,d) 
    else if(param==3) 
     DoIt(Interpolator<NoCachingStrategy,RestDataSource>(),c,d) 

} 

template<class T> 
void DoIt(const T& t, ConfigObject c, ConfigObject d) { 
    t.ConfigCache(c); 
    t.ConfigDataSource(c); 
    while(run) { 
     double input = WaitForRequest(); 
     SendRequest(t.GetValue(input)); 
    } 
} 

जब मैं एक टेम्पलेट आधारित कार्यान्वयन के लिए OOP कार्यान्वयन बदलने की कोशिश, क्षेपक कोड एक के बिना अनुवाद किया जा सकता बहुत दर्द असल में, टेम्पलेट प्रकार पैरामीटर के साथ "इंटरफेस" को प्रतिस्थापित करें, और स्ट्रैटेजी/डेटासोर्स या कॉन्फ़िगरेशन पैरामीटर के उदाहरण में पास करने के लिए एक तंत्र जोड़ें।

लेकिन जब मैं "मुख्य" पर जाता हूं, तो यह मुझे स्पष्ट नहीं है कि टेम्पलेट मेटा प्रोग्रामिंग की शैली में टेम्पलेट का लाभ उठाने के लिए इसे कैसे लिखा जाना चाहिए। मैं अक्सर बहुरूपता का उपयोग करना चाहता हूं, लेकिन यह टेम्पलेट्स के साथ अच्छी तरह से खेलना प्रतीत नहीं होता है (कभी-कभी ऐसा लगता है कि मुझे जावा के टाइप-एरर जेनरिक की आवश्यकता है ... यूघ)।

जब मुझे अक्सर लगता है कि मैं ऐसा करना चाहता हूं तो TemplateType<?,?> x = new TemplateType<X,Y>() जैसा कुछ है, जहां x X, Y है।

वास्तव में, टेम्पलेट का उपयोग करते समय यह अक्सर मेरी समस्या होती है।

  1. क्या मुझे टेम्पलेट्स का एक और स्तर लागू करने की आवश्यकता है?
  2. क्या मैं पर अपने चमकदार नए पावर टेम्पलेट रिंच का उपयोग करने की कोशिश कर रहा हूं, एक पीसीआई स्लॉट में ओओपी नाखून स्थापित करें?
  3. या क्या मैं टेम्पलेट प्रोग्रामिंग की बात करते समय यह सब गलत सोच रहा हूं?

[संपादित करें] कुछ लोगों ने इंगित किया है कि यह वास्तव में टेम्पलेट मेटाप्रोग्रामिंग नहीं है इसलिए मैंने प्रश्न को थोड़ा सा हल किया है। शायद यह समस्या का हिस्सा है - मैंने अभी तक टीएमपी वास्तव में क्या किया है।

उत्तर

23

टेम्पलेट्स स्थिर बहुरूपता बताते हैं: आप रणनीति को लागू करने, संकलन समय पर टेम्पलेट पैरामीटर निर्दिष्ट करें। वे गतिशील polymorphism प्रदान नहीं करते हैं, जहां आप वर्चुअल सदस्य कार्यों के साथ रनटाइम पर एक वस्तु की आपूर्ति करते हैं जो रणनीति को लागू करते हैं।

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

आप प्रकार MyTemplate<?> (पहले यह instantiated है एक और टेम्पलेट में प्रदर्शित होने को छोड़कर) के एक चर नहीं हो सकता। MyTemplate<X> और MyTemplate<Y> पूरी तरह से असंबंधित कक्षाएं हैं (भले ही एक्स और वाई संबंधित हैं), जो शायद समान कार्य करने के लिए होते हैं यदि वे उसी टेम्पलेट से तत्काल होते हैं (जिन्हें वे नहीं होना चाहिए - एक विशेषज्ञता हो सकती है)। भले ही वे हैं, यदि टेम्पलेट पैरामीटर किसी भी सदस्य फ़ंक्शन के हस्ताक्षर में शामिल है, तो वे फ़ंक्शन समान नहीं हैं, उनके पास समान नाम हैं। तो गतिशील बहुरूपता के पीओवी से, एक ही टेम्पलेट के उदाहरण किसी भी दो वर्गों के समान स्थिति में होते हैं - वे केवल तभी खेल सकते हैं जब आप उन्हें कुछ वर्चुअल सदस्य फ़ंक्शंस के साथ एक सामान्य बेस क्लास दें।

class InterpolatorInterface { 
public: 
    virtual Value GetValue(const double) = 0; 
    virtual void ConfigCache(const& ConfigObject) = 0; 
    virtual void ConfigDataSource(const& ConfigObject) = 0; 
    virtual ~InterpolatorInterface() {} 
}; 

तब:

template <typename TCacheStrategy, typename TDataSource> 
class Interpolator: public InterpolatorInterface { 
    ... 
}; 

अब तुम क्या संकलन समय पर जाना जाता है के अनुसार क्षेपक के अपने विभिन्न प्रकार बनाने के लिए टेम्पलेट का उपयोग कर रहे हैं

तो, आप एक आम आधार वर्ग को परिभाषित कर सकता है (ताकि कॉल करने के लिए रणनीतियों क्षेपक से गैर आभासी कर रहे हैं), और आप गतिशील बहुरूपता का उपयोग कर रहे भले ही आप जब तक क्रम जो एक आप चाहते हैं (ताकि क्षेपक के लिए ग्राहक से कॉल कर रहे हैं पता नहीं है उन्हें एक ही इलाज के लिए आभासी)। आपको बस याद रखना होगा कि दोनों बहुत ही पूरी तरह से स्वतंत्र तकनीक हैं, और प्रत्येक का उपयोग करने के फैसले काफी असंबद्ध हैं।

Btw, इस मेटा प्रोग्रामिंग टेम्पलेट नहीं है, यह सिर्फ टेम्पलेट का उपयोग कर रहा है।

संपादित करें। टीएमपी क्या है, यहां कैननिकल प्रारंभिक उदाहरण है:

#include <iostream> 

template<int 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 << "12! = " << Factorial<12>::value << "\n"; 
} 

उस 12 का निरीक्षण करें! कंपाइलर द्वारा की गणना की गई है, और एक संकलन-समय स्थिर है। यह रोमांचक है क्योंकि यह पता चला है कि सी ++ टेम्पलेट सिस्टम एक ट्यूरिंग-पूर्ण प्रोग्रामिंग भाषा है, जो सी प्रीप्रोसेसर नहीं है। संसाधन सीमाओं के अधीन, आप संकलन समय पर मनमाने ढंग से गणना कर सकते हैं, परिस्थितियों में रनटाइम ओवरहेड से परहेज करते हैं जहां आप संकलन समय पर इनपुट जानते हैं। टेम्पलेट्स अपने टेम्पलेट पैरामीटर को एक कार्यात्मक भाषा जैसे हेरफेर कर सकते हैं, और टेम्पलेट पैरामीटर पूर्णांक या प्रकार हो सकते हैं। या कार्यों, हालांकि उन संकलन समय पर "बुलाया" नहीं जा सकता है। या अन्य टेम्पलेट्स, हालांकि उन्हें संरचना के स्थिर सदस्यों के रूप में "वापस" नहीं किया जा सकता है।

+3

+1 यह इंगित करने के लिए कि यह टेम्पलेट मेटा-प्रोग्रामिंग नहीं है। –

7

मुझे टेम्पलेट्स और पॉलिमॉर्फिज्म अच्छी तरह से काम करते हैं। आपके उदाहरण में यदि क्लाइंट कोड परवाह नहीं है कि कौन सा टेम्पलेट पैरामीटर इंटरपोलेटर उपयोग कर रहा है तो टेम्पलेट उप-वर्गों को एक सार बेस क्लास पेश करें। उदा .:

class Interpolator 
{ 
public: 
    virtual Value GetValue (const double) = 0; 
}; 

template<class TCacheStrategy, class TDataSource> 
class InterpolatorImpl : public Interpolator 
{ 
public: 
    InterpolatorImpl(); 
    Value GetValue(const double); 
}; 

void main() 
{ 
    int param = 1; 

    Interpolator* interpolator = 0; 

    if (param==1) 
     interpolator = new InterpolatorImpl<InMemoryStrategy,TextFileDataSource>(); 
    else if (param==2) 
     interpolator = new InterpolatorImpl<InMemoryStrategy,OdbcDataSource>(); 
    else if (param==3) 
     interpolator = new InterpolatorImpl<NoCachingStrategy,RestDataSource>(); 

    while (true) 
    { 
     double input = WaitForRequest(); 
     SendRequest(interpolator->GetValue (input)); 
    } 
} 

मैं इस मुहावरे का काफी उपयोग करता हूं। यह क्लाइंट कोड से टेम्पलेट सामान को अच्छी तरह से छुपाता है।

नोट, मुझे यकीन नहीं है कि टेम्पलेट्स का उपयोग वास्तव में "मेटा प्रोग्रामिंग" के रूप में कक्षाओं के रूप में करता है। मैं आमतौर पर अधिक परिष्कृत संकलन-समय टेम्पलेट चाल के उपयोग के लिए उस भव्य शब्द को आरक्षित करता हूं, संकलन समय पर सामग्री की प्रभावी गणना करने के लिए सशर्तों, पुनरावर्ती परिभाषा आदि का उपयोग करता हूं।

+0

लेकिन ऐसा करके, आप पहली जगह टेम्पलेट का उपयोग करने के अधिकांश लाभ खो देते हैं। – jalf

+0

@jalf: यह सच नहीं है, हालांकि मैं समझता हूं कि आप कहां से आ रहे हैं। इस उत्तर में, टेम्पलेट्स का उपयोग प्रत्येक इंटरपोलेटर आईएमएलएल इंस्टेंटेशन को संकलित-समय अनुकूलित (इनलाइनिंग, डेड कोड एलिमिनेशन, लूप अनोलिंग इत्यादि) होने की अनुमति देता है, केवल शीर्ष-स्तर GetValue कॉल को वर्चुअल रूप से प्रेषित करने की आवश्यकता होती है, और कार्यान्वयन की सभी जटिलताओं अधिक होती हैं कुशल। चाहे वह कुछ भी लायक है, पूरी तरह निर्भर करता है कि कार्यान्वयन कितना जटिल है। टेम्पलेट्स और आभासी प्रेषण का एक अच्छा मिश्रण प्रोग्रामर को इष्टतम संतुलन को ट्यून करने की अनुमति देता है। –

6

टेम्पलेट्स को कभी-कभी स्थैतिक (या संकलन-समय) पॉलिमॉर्फिज्म कहा जाता है, इसलिए हां, कभी-कभी ओओपी (गतिशील) बहुरूपता के बजाय उन्हें कभी भी उपयोग किया जा सकता है। बेशक, इसे रनटाइम की बजाय संकलन-समय पर निर्धारित करने की आवश्यकता होती है, इसलिए यह गतिशील बहुरूपता को पूरी तरह से प्रतिस्थापित नहीं कर सकता है।

जब मुझे अक्सर लगता है कि मैं ऐसा करना चाहता हूं तो टेम्पलेट टाइप x = new TemplateType() जैसे एक्स है, एक्स एक्स परवाह नहीं करता है, एक्स क्या है।

हाँ, यह संभव नहीं है। आपको DoIt() फ़ंक्शन के साथ जो कुछ है उसके समान कुछ करना है। अक्सर, मुझे लगता है कि एक क्लीनर समाधान को समाप्त होता है (आप छोटे कार्यों के साथ समाप्त होते हैं जो प्रत्येक एक चीज करते हैं - आम तौर पर एक अच्छी चीज)। लेकिन अगर प्रकार केवल रनटाइम पर निर्धारित होते हैं (जैसे आपके मुख्य फ़ंक्शन के ओओपी संस्करण में i के साथ), तो टेम्पलेट काम नहीं करेंगे।

लेकिन इस मामले में, मुझे लगता है कि आपका टेम्पलेट संस्करण समस्या को हल करता है, और यह अपने आप में एक अच्छा समाधान है। (हालांकि एक्यूबोन का उल्लेख है, इसका मतलब है कि सभी तीन टेम्पलेट्स के लिए कोड तत्काल हो जाता है, जो कुछ मामलों में हो सकता है)

+0

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

+0

@ जेम्स: एक लापरवाही प्लग का बिट, लेकिन यदि आप इस पर अस्पष्ट नहीं हैं तो आप यहां मेरा जवाब पढ़ना चाहेंगे - http://stackoverflow.com/questions/5854581/polymorphism-in-c/5854862#5854862 –

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