2015-12-06 12 views
7

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

struct Foo { 
    virtual void fn() = 0; 
}; 

template<class T> 
struct Bar: public Foo { 
    void fn() override { 
     T{}.fn(); 
    } 
}; 

struct S { 
    void fn() { } 
}; 

int main() { 
    Foo *foo = new Bar<S>{}; 
    foo->fn(); 
} 

क्या मैं के साथ के बाद से एक घंटे पहले (या यहां तक ​​कि अगर वहाँ एक विकल्प मुहावरा मौजूद है) उसे बदलने का तरीका है एक variadic टेम्पलेट सदस्य विधि लागू करने के लिए संघर्ष कर रहा हूँ।
जाहिर है, मैं Foo वर्ग के फ़ंक्शन को संशोधित नहीं कर सकता, क्योंकि यह एक आभासी है और वर्चुअल विनिर्देशक टेम्पलेट्स के साथ नहीं जाता है। Bar के विनिर्देश के लिए मान्य है, क्योंकि इसे बेस क्लास में किसी भी तरह से ओवरराइड करना है।

नोट।

मैं दृढ़ता से संदेह के लिए इस सवाल का सबसे बड़ा XYProblem कभी देखा में से एक हो सकता है, मैं यह भी पसंद वास्तविक समस्या का एक संक्षिप्त विवरण देने के लिए चाहते हैं।

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

  • पहले एक एक टेम्पलेट वर्ग T जाता है कि तुरंत इस्तेमाल नहीं स्वीकार करता है, बजाय इसे संग्रहीत होना चाहिए किसी भी तरह के क्रम में बाद में प्रयोग की जाने वाली ।

  • दूसरा दूसरा तर्कों की एक भिन्न संख्या स्वीकार करता है (यह वास्तव में एक विविध टेम्पलेट सदस्य कार्य है) और उन तर्कों को T के नव निर्मित उदाहरण के लिए पूरी तरह से अग्रेषित किया जाना चाहिए।

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

संपादित

मुझे लगता है कि यह किसी भी तरह उच्च आदेश कार्यों के समान है।
मेरा मतलब है, समस्या का समाधान क्या होगा वास्तव में एक तर्कसंगत कार्य है जिसमें पहली तर्क को बांधना है, लेकिन जहां तक ​​मुझे पता है कि यह असंभव है और साथ ही साथ किसी भी अन्य दृष्टिकोण को मैंने अभी तक खोजा है।
कोई व्यवहार्य समाधान जो एक ही अवधारणा को व्यक्त करता है?तो अब

template<typename T> class Factory { 

public: 
    template<typename ...Args> 
    auto construct(Args && ...args) 
    { 
     return T(std::forward<Args>(args)...); 
    } 
}; 

, अपने पहले उजागर वर्ग विधि कुछ इस तरह होगा::

+0

आपका बड़ा लक्ष्य रनटाइम और संकलन-समय गतिशीलता को गठबंधन करना है जिस तरह से मुझे संदेह है कि संभव नहीं है, लेकिन मुझे यह देखने के लिए उत्सुकता होगी कि मेरे साथ क्या चतुर लोग आते हैं। – zwol

+0

@zwol मुझे बिल्कुल वही अनुभव है, यही कारण है कि मैंने SO पर पूछा है !! :-) – skypjack

+0

निश्चित रूप से, * सदस्य फ़ंक्शन टेम्पलेट वर्चुअल * –

उत्तर

6

मैं टिप्पणी में क्या उल्लेख निम्नलिखित दृष्टिकोण है

template<typename T> 
auto getFactory() { 

    return Factory<T>(); 
} 

तो:

auto factory=object.getFactory<someClass>(); 

// Then later: 

factory.construct(std::string("Foo"), bar()); // And so on... 

construct() के बजाय आप operator() भी उपयोग कर सकते हैं, इसलिए वें का दूसरा भाग बन जाता है, बस:

factory(std::string("Foo"), bar()); // And so on... 

जैसा कि मैंने उल्लेख किया है, यह वास्तव में मिटा नहीं है। आप यहां टाइप एरर का उपयोग नहीं कर सकते हैं।

यह कुछ मिनटों के विचार को देखते हुए, कारण टाइप करने का कारण यहां उपयोग नहीं किया जा सकता है क्योंकि टाइप एरर का एक दिया गया उदाहरण "स्वयं निहित" होना चाहिए, या परमाणु, और आपको जो करना है उसे तोड़ना है परमाणु प्रकार आपके मामले में दो भागों, या दो वर्ग विधियों में मिटा देता है।

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

आप टेम्पलेट वर्ग और कन्स्ट्रक्टर पैरामीटर को एक साथ टाइप कर सकते हैं। आप टेम्प्लेट क्लास, और कन्स्ट्रक्टर पैरामीटर को अलग-अलग टाइप नहीं कर सकते हैं और फिर किसी भी तरह से परिणाम फिर से टाइप-मिटा सकते हैं।

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

+0

प्रयास के कारण उपरोक्त, वैसे भी मुझे यकीन नहीं है कि यह समस्या हल करता है। इसके अलावा, शायद आपने मुझे एक अच्छा विचार दिया। कल मुझे जाना होगा और अधिक प्रश्नों के साथ वापस आना होगा। – skypjack

+0

जैसा कि आपने पहले से ही उल्लेख किया है, यह किसी साधारण कारण के लिए समस्या का समाधान नहीं करता है: या तो मुझे 'टी' टाइप करने की आवश्यकता होती है जब मुझे कारखाने बनाने के लिए 'Args ...' मिलता है, या किसी भी तरह से मुझे एक ऐसा कारखाना बनाना चाहिए जो नहीं कर सकता टाइप-मिस्ड हो और इसे कहीं भी स्टोर करने के लिए इसे टाइप करें। – skypjack

+0

सी ++ में यह असंभव है, क्योंकि टेम्पलेट वर्चुअल नहीं हो सकते हैं। इस तरह कुछ करने का एकमात्र तरीका वर्ग के रचनाकारों के लिए एक टाइप-मिटाए गए पैरामीटर पैक को स्वीकार करना है। फिर, आप कक्षा को टाइप-मिटते हैं, और एक टाइप-मिस्ड वर्चुअल फ़ंक्शन प्रदान करते हैं जो एक टाइप-मिटाए गए पैरामीटर पैक को स्वीकार करता है, और फिर कन्स्ट्रक्टर को आमंत्रित करता है। –

4

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

struct Delay // I have no idea what to call this 
    { 
     template <class T> 
     void SetT() 
     { 
      function_ = [](boost::any params){return T(params);} 
     } 

     template <class ... Args> 
     boost::any GetT(Args ... args) 
     { 
      return function_(std::make_tuple(args...)); 
     } 

     private: 
     std::function<boost::any(boost::any)> function_; 
    }; 

इस बात का स्पष्ट सीमा यह है कि GetT बुला किसी को भी किसी भी तरह, पता है कि T पहले से ही था, हालांकि आप अपने वर्ग के type_info के लिए boost::any वस्तु क्वेरी कर सकता है कि अगर मदद करता होगा। यहां दूसरी सीमा यह है कि आपको T में पास करना होगा जो boost::any ऑब्जेक्ट लेता है और पता है कि इसके साथ क्या किया जाए। आप T है, तो कर सकते हैं नहीं है, तो आप SetT बदल सकते हैं (या एक नया सदस्य समारोह बनाने) इस तरह:

template <class F> 
    SetTFactory(F f) 
    { 
     function_ = f; 
    } 

और उसके बाद का उपयोग यह पसंद:

Delay d; 
    d.SetTFactory([](boost::any s){return std::string(boost::any_cast<const char*>(s));}); 
    auto s = d.GetT("Message"); 
    assert(s.type() == typeid(std::string)); 

निश्चित रूप से यह एक पूरी परिचय निपटने के लिए कठिनाइयों का नया सेट, इसलिए मुझे नहीं पता कि यह समाधान आपके लिए कितना व्यवहार्य होगा। मुझे लगता है कि किसी और चीज के बावजूद, आपको अपने डिजाइन पर थोड़ा सा विचार करना होगा।

+0

वास्तव में बहुत मुश्किल है। धन्यवाद। – skypjack

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