C ++ में आंतरिक टाइपफेड - अच्छी शैली या बुरी शैली?


179

कुछ ऐसा जो मैंने खुद पाया है कि हाल ही में उस वर्ग के अंदर एक विशेष वर्ग के लिए प्रासंगिक टाइपफेड घोषित कर रहा है, अर्थात

class Lorem
{
    typedef boost::shared_ptr<Lorem> ptr;
    typedef std::vector<Lorem::ptr>  vector;

//
// ...
//
};

इन प्रकारों का उपयोग कोड में कहीं और किया जाता है:

Lorem::vector lorems;
Lorem::ptr    lorem( new Lorem() );

lorems.push_back( lorem );

कारण मुझे यह पसंद है:

  • यह क्लास के टेम्प्लेट, std::vector<Lorem>बन Lorem::vector, आदि द्वारा शुरू किए गए शोर को कम करता है ।
  • यह आशय के एक कथन के रूप में कार्य करता है - ऊपर के उदाहरण में, लोरम वर्ग को boost::shared_ptrएक वेक्टर में के माध्यम से गिना और संग्रहीत किया गया संदर्भ माना जाता है।
  • यह कार्यान्वयन को बदलने की अनुमति देता है - अर्थात यदि लोरेम को boost::intrusive_ptrबाद के चरण में आंतरिक रूप से संदर्भित (के माध्यम से ) को बदलने की आवश्यकता होती है तो इससे कोड पर न्यूनतम प्रभाव पड़ेगा।
  • मुझे लगता है कि यह 'प्रीतिकर' लगता है और यकीनन पढ़ने में आसान है।

कारण मुझे यह पसंद नहीं है:

  • निर्भरता के साथ कभी-कभी मुद्दे होते हैं - यदि आप एक Lorem::vectorअन्य वर्ग के भीतर , कहना चाहते हैं, लेकिन केवल लोरेम को आगे बढ़ाने की आवश्यकता है (या चाहते हैं) (जैसा कि इसकी हेडर फ़ाइल पर निर्भरता शुरू करने का विरोध किया गया है) तो आप का उपयोग करना समाप्त होता है। स्पष्ट प्रकार (उदाहरण के boost::shared_ptr<Lorem>बजाय Lorem::ptr), जो थोड़ा असंगत है।
  • यह बहुत आम नहीं हो सकता है, और इसलिए समझना मुश्किल है?

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

जवाबों:


153

मुझे लगता है कि यह उत्कृष्ट शैली है, और मैं इसे स्वयं उपयोग करता हूं। जितना संभव हो सके नामों के दायरे को सीमित करना हमेशा सबसे अच्छा होता है, और सी ++ में ऐसा करने के लिए कक्षाओं का उपयोग सबसे अच्छा तरीका है। उदाहरण के लिए, C ++ मानक पुस्तकालय कक्षाओं के भीतर टाइप किए गए शब्दों का भारी उपयोग करता है।


यह एक अच्छा बिंदु है, मुझे आश्चर्य है कि यह 'प्रीटियर' लग रहा था मेरा अवचेतन नाजुक रूप से इंगित कर रहा था कि सीमित गुंजाइश एक अच्छी बात है। मुझे आश्चर्य है कि, क्या तथ्य यह है कि एसटीएल इसे मुख्य रूप से कक्षा के खाके में उपयोग करता है, यह इसे एक अलग तरह का उपयोग करता है? क्या to ठोस ’वर्ग में औचित्य करना कठिन है?
विल बेकर

1
वैसे मानक पुस्तकालय कक्षाओं के बजाय टेम्पलेट्स से बना है, लेकिन मुझे लगता है कि दोनों के लिए औचित्य समान है।

14

यह आशय के एक बयान के रूप में कार्य करता है - ऊपर के उदाहरण में, लोरम वर्ग को बढ़ावा देने के उद्देश्य से संदर्भित किया जाता है :: साझा_प्रति और वेक्टर में संग्रहीत।

यह ठीक यही है जो यह नहीं करता है।

यदि मुझे कोड में 'Foo :: Ptr' दिखाई देता है, तो मुझे बिल्कुल पता नहीं है कि क्या यह एक साझा_प्रति या Foo * है (STL में :: पॉइंटर टाइपफेड जो कि T * हैं, याद रखें) या जो भी हो। Esp। यदि यह एक साझा सूचक है, तो मैं बिल्कुल भी एक टाइफाइड प्रदान नहीं करता हूं, लेकिन कोड में साझा रूप से उपयोग को स्पष्ट रूप से रखें।

दरअसल, मैं शायद ही कभी टेम्प्लेट Metaprogramming के बाहर टाइप-एफ का उपयोग करता हूं।

एसटीएल हर समय इस प्रकार की बात करता है

सदस्य कार्यों और नेस्टेड टाइपराइफ के संदर्भ में परिभाषित अवधारणाओं के साथ एसटीएल डिजाइन एक ऐतिहासिक कार्य-डी-थैली है, आधुनिक टेम्पलेट लाइब्रेरी नि: शुल्क कार्यों और लक्षणों की कक्षाओं का उपयोग करती है (cf. Boost.Graph), क्योंकि ये बिल्ट-इन प्रकारों को बाहर नहीं करते हैं कॉन्सेप्ट को मॉडलिंग करना और क्योंकि यह एडाप्टिंग प्रकार बनाता है जो कि दिए गए टेम्प्लेट लाइब्रेरी के कॉन्सेप्ट्स को ध्यान में रखकर डिजाइन नहीं किया गया था।

उसी गलतियों को करने के लिए एसटीएल का उपयोग एक कारण के रूप में न करें।


मैं आपके पहले भाग से सहमत हूं, लेकिन आपका हालिया संपादन थोड़ा अदूरदर्शी है। इस तरह के नेस्टेड प्रकार विशेषता वर्गों की परिभाषा को सरल बनाते हैं, क्योंकि वे एक समझदार डिफ़ॉल्ट प्रदान करते हैं। नई std::allocator_traits<Alloc>कक्षा पर विचार करें ... आपको इसे लिखने वाले हर एक आवंटनकर्ता के लिए विशेषज्ञ बनाने की आवश्यकता नहीं है, क्योंकि यह सीधे प्रकार से उधार लेता है Alloc
डेनिस ज़िकफोस

@ डेनिस: C ++ में, सुविधा पुस्तकालय के / उपयोगकर्ता / पक्ष की तरफ होनी चाहिए, उसके लेखक / लेखक की तरफ नहीं: /: उपयोगकर्ता एक विशेषता के लिए एक समान इंटरफ़ेस की इच्छा रखता है, और केवल एक विशेषता वर्ग ही ऐसा दे सकता है, ऊपर दिए गए कारणों की वजह से)। लेकिन एक Allocलेखक के रूप में भी , std::allocator_traits<>अपने नए प्रकार के लिए विशेषज्ञ के रूप में यह आवश्यक नहीं है कि वह आवश्यक टाइपराइफ को जोड़ सके। मैंने उत्तर को संपादित भी कर दिया है, क्योंकि मेरा पूरा उत्तर टिप्पणी में फिट नहीं हुआ।
मार्क मुत्ज़ - mmutz

लेकिन यह है उपयोगकर्ता के पक्ष में। एक कस्टम आवंटनकर्ता बनाने के प्रयास के उपयोगकर्ता के रूप में allocator_traits, मुझे गुण वर्ग के पंद्रह सदस्यों के साथ परेशान नहीं होना है ... मुझे केवल इतना करना है कि typedef Blah value_type;उचित सदस्य कार्य कहे और प्रदान करें, और डिफ़ॉल्ट allocator_traitsका पता चलेगा आराम। इसके अलावा, Boost.Graph के अपने उदाहरण को देखें। हां, यह विशेषता वर्ग का भारी उपयोग करता है ... लेकिन अपने स्वयं के आंतरिक टाइपराइफ के लिए graph_traits<G>बस प्रश्नों का डिफ़ॉल्ट कार्यान्वयन G
डेनिस ज़िकफ़ोज़ो

1
और यहां तक ​​कि 03 मानक पुस्तकालय भी गुण वर्गों का उपयोग करता है जहां उपयुक्त ... पुस्तकालय का दर्शन उदारतापूर्वक कंटेनरों पर काम करना नहीं है, लेकिन पुनरावृत्तियों पर काम करना है। तो यह एक iterator_traitsवर्ग प्रदान करता है ताकि आपके जेनेरिक एल्गोरिदम उचित जानकारी के लिए आसानी से क्वेरी कर सकें। जो, पुन: अपनी सूचना के लिए पुनरावृत्त को क्वेरी करने में चूक करता है। इसका लंबा और छोटा मतलब यह है कि लक्षण और आंतरिक टाइपफेड शायद ही परस्पर अनन्य हैं ... वे एक दूसरे का समर्थन करते हैं।
डेनिस ज़िकफ़ोज़ो

1
@ डेनिस: iterator_traitsआवश्यक हो गया क्योंकि T*एक मॉडल होना चाहिए RandomAccessIterator, लेकिन आप आवश्यक टाइपराइफ को नहीं डाल सकते T*। एक बार हमारे पास iterator_traits, नेस्टेड टाइफेड निरर्थक हो गए थे, और मैं चाहता हूं कि उन्हें वहां से हटा दिया गया था। एक ही कारण के लिए (आंतरिक टंकण जोड़ने के लिए असंभव), T[N]एसटीएल Sequenceअवधारणा को मॉडल नहीं करता है , और आपको इस तरह के क्लूज की आवश्यकता होती है std::array<T,N>। Boost.Range दिखाता है कि एक आधुनिक अनुक्रम अवधारणा को कैसे परिभाषित किया जा सकता है जो T[N]मॉडल कर सकता है, क्योंकि इसके लिए नस्टेड टाइपराइफ की आवश्यकता नहीं है, न ही सदस्य कार्यों की।
मार्क मुत्ज़ - एमएमयूटीज़


8

टाइपडेफ्स निश्चित रूप से अच्छी शैली हैं। और आपके सभी "कारण मुझे पसंद हैं" अच्छे और सही हैं।

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

आप क्लास के बाहर टाइपडीफ ले जा सकते हैं लेकिन क्लास :: ptr इतना प्रेटियर है तो क्लासपार्ट कि मैं ऐसा नहीं करता। यह मेरे लिए जैसे नामस्थान के साथ है - चीजें दायरे के भीतर जुड़ी रहती हैं।

कभी-कभी मैंने किया

Trait<Loren>::ptr
Trait<Loren>::collection
Trait<Loren>::map

और यह सभी डोमेन वर्गों के लिए और कुछ लोगों के लिए कुछ विशेषज्ञता के साथ डिफ़ॉल्ट हो सकता है।


3

एसटीएल हर समय इस प्रकार की बात करता है - टाइपलेफ एसटीएल में कई वर्गों के लिए इंटरफ़ेस का हिस्सा हैं।

reference
iterator
size_type
value_type
etc...

सभी एसटीएल टेम्प्लेट कक्षाओं के लिए इंटरफ़ेस का हिस्सा हैं जो सभी टाइप किए गए हैं।


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

3

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

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


3

वर्तमान में मैं कोड पर काम कर रहा हूं, जो गहनता से इन प्रकार के टाइपफेड का उपयोग करता है। अब तक जो ठीक है।

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

इसलिए उनका उपयोग करने से पहले, कुछ बिंदुओं पर विचार किया जाना चाहिए

  • क्या किसी और को इन टाइप्डिफ की जरूरत है? क्या अन्य वर्गों द्वारा कक्षा का बहुत उपयोग किया जाता है?
  • क्या मैंने उपयोग को छोटा कर दिया है या कक्षा को छिपा दिया है? (छिपाने के मामले में आप इंटरफेस के बारे में भी सोच सकते हैं।)
  • क्या अन्य लोग कोड के साथ काम कर रहे हैं? वह यह कैसे करते हैं? क्या वे सोचेंगे कि यह आसान है या वे भ्रमित हो जाएंगे?

1

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

आपके द्वारा पसंद किए जाने वाले कारण अभी भी मेल खाते हैं, क्योंकि वे टाइप एफ़ेडिंग के माध्यम से हल कर रहे हैं, न कि उन्हें उनकी कक्षा के अंदर घोषित करके।


अनाम टाइप के साथ अनाम नेमस्पेस polute होगा यह नहीं होगा ?! टंकण के साथ समस्या यह है कि यह वास्तविक प्रकार को छुपाता है, जो कई मॉड्यूलों द्वारा / में शामिल किए जाने पर टकराव का कारण बन सकता है, जिसे ढूंढना / ठीक करना मुश्किल है। यह नामस्थान या कक्षाओं के अंदर रखने के लिए एक अच्छा अभ्यास है।
Indy9000

3
नाम संघर्ष और अनाम नेमस्पेस पॉल्यूशन का एक वर्ग या बाहर टाइपनेम रखने से बहुत कम है। आप अपने वर्ग के साथ एक नाम संघर्ष कर सकते हैं, न कि आपके टाइपडेफ़्स के साथ। इसलिए नाम पॉल्यूशन से बचने के लिए नेमस्पेस का इस्तेमाल करें। अपनी कक्षा और संबंधित टाइपराइफ़ को एक नाम स्थान में घोषित करें।
Cătălin Pitiș

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

1

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

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