2013-02-28 12 views
5

में स्वीकार करने "कुछ भी" मैं एक साधारण टेम्पलेट struct एक मूल्य के साथ एक स्ट्रिंग जोड़ हैटेम्पलेट्स सी ++

template<typename T> struct Field 
{ 
    std::string name; T self; 
} 

मैं एक समारोह है कि मैं 1 या अधिक किसी भी प्रकार की फील्ड्स को स्वीकार करना चाहते है, और फ़ील्ड संभवतः विभिन्न प्रकार के हो सकते हैं, इसलिए मैं std::initializer_list का उपयोग कर रहा हूं क्योंकि सी ++, मेरे ज्ञान के लिए, टाइप किए गए वैरैडिक तर्कों की कमी है, वे विविध तर्कों का आकार निर्धारित नहीं कर सकते हैं, और यह निर्धारित करने के लिए कम से कम एक अन्य तर्क होना चाहिए कि कहां से शुरू करना है।

समस्या यह है कि मुझे नहीं पता कि विभिन्न क्षेत्रों के क्षेत्र को स्वीकार करने के लिए इसे कैसे बताना है। जावा में, मैं बस foo(Field<?> bar, Field<?>... baz) का उपयोग करूंगा, लेकिन सी ++ में टाइप किए गए वैरैडिक तर्क और वाइल्डकार्ड दोनों की कमी है। मेरा एकमात्र अन्य विचार std::initializer_list<Field<void*>> के पैरामीटर को बनाना है, लेकिन यह एक खराब समाधान की तरह लगता है ... क्या ऐसा करने का कोई बेहतर तरीका है?

+2

विभिन्न टेम्पलेट तर्कों के साथ एक ही टेम्पलेट के इंस्टेंटेशन पूरी तरह से असंबंधित प्रकार हैं। एक बार आपके पास 'फ़ील्ड' ऑब्जेक्ट्स के साथ क्या करने की योजना है? सी ++ * करता है * [वैरैडिक टेम्पलेट्स] (http://en.wikipedia.org/wiki/Variadic_template) (जिसका उपयोग टाइपएफ़ वैरिएडिक फ़ंक्शंस बनाने के लिए किया जा सकता है)। – Mankarse

+0

फ़ंक्शन केवल बाद में वेक्टर में प्रत्येक फ़ील्ड को छीनने जा रहा है, इसलिए मुझे वास्तव में परवाह नहीं है कि उनके प्रकार _are_ क्या हैं। सी ++ के variadics के प्रकार के सुरक्षा यहाँ, एक माध्यमिक चिंता वास्तव में है, क्योंकि कोड दुर्घटनाओं जब आप बुरा प्रकार में भेज अगर, अच्छी तरह से है कि तब ऐसा नहीं करते हैं (जो कोड है रक्षा और प्रकार की जाँच अपने आप को इससे पहले कि आप फ़ंक्शन को कॉल करें) । मैं जानता हूँ कि फील्ड और फील्ड वास्तव में संबंधित नहीं हैं कि (गैर (सह/विपरीत) -variance असंभव बना दिया (ठीक है, वास्तव में नहीं है, लेकिन द्वारा अजीब बनाया) गैर-वर्ग टेम्पलेट पैरामीटर)। –

+0

@MattG तो फ़ील्ड सभी _one_ वेक्टर में जाते हैं? उस मामले में एक और भी कठिन सवाल यह होगा कि उस वेक्टर का प्रकार क्या होना चाहिए। – jogojapan

उत्तर

0

यह सी ++ के लिए बहुत मूर्ख नहीं है। यह किया जा सकता है, शायद; कोप्लिअन की किताब में कुछ विचार हो सकते हैं। लेकिन सी ++ दृढ़ता से टाइप किया गया है क्योंकि यह टाइपिंग में विश्वास करता है; इसे स्मॉलटाक में बदलने की कोशिश कर रहा है या इसे एक फिजेंट की तरह फोल्ड कर सकता है जिससे आँसू हो सकते हैं।

4

जावा जेनरिक boost::any को self चर में C++ टेम्पलेट्स की तुलना में बस भरने के करीब हैं। कोशिश करो। सी ++ टेम्पलेट्स ऐसे प्रकार बनाते हैं जिनमें डिफ़ॉल्ट रूप से कोई रनटाइम या गतिशील रिलायंसशिप नहीं होती है।

आप एक सामान्य माता-पिता के माध्यम से मैन्युअल रूप से ऐसे रिश्ते को पेश कर सकते हैं और pImpl और स्मार्ट पॉइंटर्स के विवेकपूर्ण उपयोग टाइप कर सकते हैं।

सी प्रकार भिन्नता तर्क सी ++ 11 में शैली से बाहर हैं। वेरियर्डिक टेम्पलेट तर्क बहुत ही सुरक्षित हैं, जब तक आपके कंपाइलर के लिए समर्थन है (एमएसवीसी 2012 के लिए नवंबर 2012 सीटीपी के लिए समर्थन (1, सीटीपी अपडेट नहीं), जैसा कि क्लैंग और जीसीसी के गैर-प्राचीन संस्करण हैं)।

सी ++ में टेम्पलेट्स मेटाप्रोग्रामिंग का एक प्रकार है, जो एक प्रोग्राम लिखने के करीब है जो जावा जेनरिक के मुकाबले एक प्रोग्राम लिखता है। जावा जेनेरिक में एक "बाइनरी" कार्यान्वयन साझा किया गया है, जबकि सी ++ टेम्पलेट का प्रत्येक उदाहरण एक पूरी तरह से अलग "प्रोग्राम" है (जो, COMDAT फोल्डिंग जैसी प्रक्रियाओं के माध्यम से, एक बाइनरी कार्यान्वयन में घटाया जा सकता है), जिसका विवरण टेम्पलेट द्वारा वर्णित है कोड।

template<typename T> 
struct Field { 
    T data; 
}; 

एक छोटा प्रोग्राम है जो कहता है "यहां फील्ड प्रकार कैसे बनाएं"। जब आप एक int और double में गुजरती हैं, संकलक इस तरह मोटे तौर पर कुछ करता है:

struct Field__int__ { 
    int data; 
}; 
struct Field__double__ { 
    double data; 
}; 

और जैसा कि आप उम्मीद नहीं होता इन दो प्रकार के बीच परिवर्तनीय किया जाना है।

struct Field { 
    boost::any __data__; 
    template<typename T> 
    T __get_data() { 
    __data__.get<T>(); 
    } 
    template<typename T> 
    void __set_data(T& t) { 
    __data__.set(t); 
    } 
    property data; // reading uses __get_data(), writing uses __set_data() 
}; 

जहां boost::any एक कंटेनर है कि किसी भी प्रकार का एक उदाहरण हो सकते हैं, और data क्षेत्र के लिए उपयोग है उन accessors के माध्यम से पुनर्निर्देश:

जावा जेनरिक, दूसरे हाथ पर, कुछ इस तरह बना सकते हैं।

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

7

योग्य कुछ बातें ...

  • सी ++ 11 (जो आप लग रहे हैं जब से तुम std::initializer_list के बारे में बात कर रहे हैं के लिए) द्वारा लिखा गया variadic तर्क है, विशेष रूप से वे variadic टेम्पलेट्स नाम हैं

  • जावा जेनरिक और सी ++ टेम्पलेट्स पूरी तरह से अलग जानवरों रहे हैं। जावा जेनेरिक एक एकल प्रकार बनाते हैं जो Object का संदर्भ संग्रहीत करता है और इंटरफ़ेस में प्रकारों में स्वचालित कास्टिंग प्रदान करता है, लेकिन महत्वपूर्ण बात यह है कि यह टाइप एरर करता है।

मैं सुझाव है कि आप की समस्या को सुलझाने और कि सी में मुहावरेदार हैं आपकी समस्या के समाधान के लिए ++ सुझाव प्राप्त करना चाहते हैं समझाने। क्या तुम सच में जावा में व्यवहार की नकल करना चाहते हैं आप सी ++ में टाइप विलोपन उपयोग कर सकते हैं मैन्युअल रूप से (अर्थात का उपयोग boost::any) (जो, मैं काफी जोर देते हैं नहीं कर सकते एक अलग भाषा है और विभिन्न मुहावरों है)। लेकिन मुझे प्रोग्राम में पूर्ण प्रकार के क्षरण की आवश्यकता बहुत कम महसूस होती है ... एक प्रकार का प्रकार (boost::variant) का उपयोग करना थोड़ा और आम है।

अपने संकलक variadic टेम्पलेट्स के लिए समर्थन (सभी compilers ऐसा नहीं), तो आप हमेशा की तरह, उस के साथ खेल सकते हैं, लेकिन बाद में एक सदिश में के लिए खेतों stashing एक पूरी तरह से सामान्य दृष्टिकोण जब तक आप का उपयोग करने के लिए एक सा जटिल हो सकता है मिटाएं टाइप करें। (फिर, हल करने में समस्या क्या है? सरल समाधान हो सकते हैं ...)

+1

+1 "जावा और सी ++ के लिए अलग-अलग मुहावरे" के लिए एक और +1 और "अन्य समस्याओं को सुलझाने के लिए क्या समस्या है" –

+0

@MarkB 2 सॉकपूपेट खातों के लिए एक और +1? : पी ~ – Yakk

1

सी ++ टेम्पलेट्स में वाइल्डकार्ड का उपयोग करने की कोई आवश्यकता नहीं है, क्योंकि सी ++ में यह हमेशा प्रकार को जानता है, और "मिटाया नहीं गया" जावा में सी ++ में void foo(Field<?> bar, Field<?>... baz) विधि (या समारोह) लिखने के लिए, आप लिखते हैं:

template<class T, class... Ts> 
void foo(Field<T> bar, Field<Ts>... baz); 

प्रत्येक Field<Ts> एक अलग प्रकार का हो सकता है। फ़ंक्शन के अंदर वैरिएडिक पैरामीटर का उपयोग करने के लिए, आप बस baz... का उपयोग करें।

template<class T, class... Ts> 
void foo(Field<T> bar, Field<Ts>... baz) 
{ 
    foo2(baz...); 
} 

तुम भी, Field<Ts>... के साथ प्रकार का विस्तार कर सकते इसलिए यदि आप एक टपल में यह डाल करने के लिए (चाहते हैं तो आप उन्हें सरणी में नहीं डाल सकते, क्योंकि वे विभिन्न प्रकार के हो सकते हैं: तो आप एक और समारोह कॉल करना चाहते हैं का कहना है कि):

template<class T, class... Ts> 
void foo(Field<T> bar, Field<Ts>... baz) 
{ 
    std::tuple<Field<Ts>...> data(baz...); 
} 
+0

'std :: tuple ' के बारे में क्या? क्या यह संभव है? – user833771

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