C++ में typedef बनाम using: आधुनिक डेवलपर के लिए पूर्ण गाइड
\n\nक्या आपने कभी सोचा है कि C++ कोड में कुछ डेवलपर typedef क्यों लिखते हैं, जबकि अन्य using? ऐसा लगता है कि दोनों एक ही काम करते हैं - प्रकारों के लिए उपनाम बनाना। लेकिन क्या वास्तव में ऐसा है? यदि आप स्वच्छ, आधुनिक कोड लिखना चाहते हैं और पुरानी संरचनाओं के जाल में नहीं फंसना चाहते, तो यह लेख आपके लिए है।
हम समझेंगे कि C++ में typedef और using में क्या अंतर है, कब क्या उपयोग करें, और C++ समुदाय using की ओर क्यों झुक रहा है। तैयार हैं? चलिए शुरू करते हैं!
संक्षिप्त इतिहास: C से C++11 तक
\n\ntypedef हमारे पास C भाषा से आया है। यह किसी प्रकार के लिए उपनाम घोषित करने का क्लासिक तरीका है। यह इस तरह दिखता है:
\n\ntypedef unsigned long long ULL;\ntypedef std::vector<std::string> StringVector;\ntypedef void (*FunctionPtr)(int, double);\n\nसिंटैक्स, हल्के शब्दों में कहें तो, सबसे सहज नहीं है। विशेष रूप से फंक्शन पॉइंटर्स के साथ यह ध्यान देने योग्य है - अनुभवी डेवलपर भी कभी-कभी ऐसी घोषणाओं को पढ़ते समय अटक जाते हैं।
\n\nC++11 में एक नई संरचना आई - using (या alias declaration)। यह कहीं अधिक स्वाभाविक दिखती है:
\n\nusing ULL = unsigned long long;\nusing StringVector = std::vector<std::string>;\nusing FunctionPtr = void (*)(int, double);\n\nतुरंत दिखता है: बाईं ओर - नाम, दाईं ओर - प्रकार। यह 'असाइनमेंट' की तरह पढ़ा जाता है, जो किसी भी प्रोग्रामर के लिए सहज रूप से समझ में आता है।
\n\nमुख्य अंतर: टेम्पलेट के साथ काम करना
\n\nयहाँ typedef और using के बीच सबसे महत्वपूर्ण अंतर छिपा है। using alias templates (टेम्पलेट उपनाम) का समर्थन करता है, जबकि typedef नहीं करता।
आइए एक उदाहरण देखें। मान लीजिए आप कस्टम डिलीटर के साथ std::unique_ptr के लिए एक उपनाम बनाना चाहते हैं:
// using के साथ - आसान और सुंदर\ntemplate <typename T>\nusing CustomPtr = std::unique_ptr<T, void(*)(T*)>;\n\n// typedef के साथ - सीधे संभव नहीं!\n// संरचनाओं के माध्यम से रैपर बनाना होगा\ntemplate <typename T>\nstruct CustomPtrOld {\n typedef std::unique_ptr<T, void(*)(T*)> type;\n};\n\n// उपयोग:\nCustomPtr<int> ptr1; // using - सरल\nCustomPtrOld<int>::type ptr2; // typedef - कठिन\n\nअंतर महसूस कर रहे हैं? using कोड को स्वच्छ और छोटा बनाता है। और यदि आपको टेम्पलेट क्लास या फंक्शन के अंदर ऐसे उपनाम का उपयोग करना है, तो अंतर और भी ध्यान देने योग्य हो जाता है:
template <typename T>\nclass Container {\npublic:\n // using के साथ\n using Ptr = CustomPtr<T>;\n \n // typedef के साथ - typename और ::type चाहिए\n typedef typename CustomPtrOld<T>::type OldPtr;\n \nprivate:\n Ptr data;\n OldPtr oldData;\n};\n\nकोड की पठनीयता: स्पष्ट विजेता
\n\nसरल प्रकारों के लिए भी using पठनीयता में जीतता है। तुलना करें:
// typedef के साथ - स्पष्ट नहीं कि नाम कहाँ है, प्रकार कहाँ है\ntypedef std::map<std::string, std::vector<int>> StringToIntVectorMap;\n\n// using के साथ - सब कुछ स्पष्ट है\nusing StringToIntVectorMap = std::map<std::string, std::vector<int>>;\n\nजब आप कोड पढ़ते हैं, तो आपकी आंख स्वाभाविक रूप से बाएं से दाएं संरचना को स्कैन करती है। using इस सिद्धांत का पालन करता है: पहले नाम, फिर प्रकार। typedef आपको पहले प्रकार पढ़ने के लिए मजबूर करता है, फिर नाम - यह अंतर्ज्ञान के विरुद्ध है।
फंक्शन पॉइंटर्स: typedef का दर्द
\n\nफंक्शन पॉइंटर्स शायद कई डेवलपर्स के लिए C++ का सबसे अप्रिय हिस्सा है। और typedef उन्हें और भी भ्रमित करने वाला बनाता है:
// typedef - मंत्र की तरह पढ़ें\ntypedef void (*Callback)(int, const std::string&);\n\n// using - सामान्य वेरिएबल की तरह\nusing Callback = void (*)(int, const std