C ++ में कीवर्ड का उपयोग करने के पीछे क्या तर्क है?


145

C ++ में कीवर्ड का उपयोग करने के पीछे तर्क क्या है?

इसका उपयोग विभिन्न स्थितियों में किया जाता है और मैं यह जानने की कोशिश कर रहा हूं कि क्या उन सभी में कुछ समान है और एक कारण है कि "कीवर्ड" का उपयोग इस तरह किया जाता है।

using namespace std; // to import namespace in the current namespace
using T = int; // type alias
using SuperClass::X; // using super class methods in derived class

53
C + व्याकरण में नए कीवर्ड पेश करने वाले मानक कमिट से नफरत है।
तेह इंटर्नेट catz

4
@tehinternetsismadeofcatz अगर वह तर्क वास्तव में है, तो कृपया मुझे माफ करना मैं खुद जाऊंगा और खुद को मारूंगा।
user3111311

62
@ user3111311: आप नए आरक्षित शब्दों को पेश करने के निहितार्थ को पहचानते हैं, है ना? इसका मतलब है कि सभी मौजूदा कोड जिन्हें पहचानकर्ता नामों के रूप में इस्तेमाल किया गया था वे अचानक संकलन करने में विफल रहते हैं। यह एक बुरा है। उदाहरण के लिए, बहुत सी कोड है जो C ++ के रूप में संकलित नहीं कर सकते क्योंकि इसमें चीजें शामिल हैं int class;। यह और भी बुरा होगा अगर C ++ कोड अचानक C ++ मान्य होना बंद हो जाए।
बेन Voigt

7
@BenVoigt: int class;C ++ का उपयोग करने वाला C कोड संकलित नहीं होगा, यह तथ्य पूरी तरह से एक बुरी बात नहीं है। इसका उपयोग यह गारंटी देने के लिए किया जा सकता है कि सी कोड को सी के रूप में संकलित किया जाएगा। यह भूलना बहुत आसान है कि सी और सी ++ दो अलग-अलग भाषाएं हैं - और, व्यावहारिक रूप से, ऐसा कोड है जो वैध सी और मान्य सी ++ है, लेकिन विभिन्न शब्दार्थों के साथ।
कीथ थॉम्पसन

1
उस संबंध में, usingइससे बदतर (या बेहतर) नहीं है static। IMHO नए खोजशब्दों को पेश न करने की बात बहुत महत्वपूर्ण है क्योंकि तेह इन्टर्नेट द्वारा समझाया गया है जो कैटज़ और बेन वोइग्ट से बना है।
कैसियो नेरी

जवाबों:


114

C ++ 11 में, usingजब कीवर्ड का उपयोग किया जाता है तो type aliasवह समान होता है typedef

7.1.3.2

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

Bjarne Stroustrup एक व्यावहारिक उदाहरण प्रदान करता है:

typedef void (*PFD)(double);    // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double);    // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP

प्री-सी ++ 11, usingकीवर्ड सदस्य कार्यों को दायरे में ला सकता है। C ++ 11 में, अब आप कंस्ट्रक्टरों के लिए ऐसा कर सकते हैं (एक और ब्रेज़ेन स्ट्रॉस्ट्रुप उदाहरण):

class Derived : public Base { 
public: 
    using Base::f;    // lift Base's f into Derived's scope -- works in C++98
    void f(char);     // provide a new f 
    void f(int);      // prefer this f to Base::f(int) 

    using Base::Base; // lift Base constructors Derived's scope -- C++11 only
    Derived(char);    // provide a new constructor 
    Derived(int);     // prefer this constructor to Base::Base(int) 
    // ...
}; 

एक नए कीवर्ड या नए सिंटैक्स को पेश न करने के औचित्य के पीछे बेन वोइट एक बहुत अच्छा कारण प्रदान करता है। मानक जितना संभव हो उतना पुराने कोड को तोड़ने से बचना चाहता है। यही कारण है कि प्रस्ताव दस्तावेजों में आप वर्गों की तरह देखेंगे Impact on the Standard, Design decisionsऔर वे बड़े कोड कैसे प्रभावित कर सकते। ऐसी स्थितियाँ होती हैं जब कोई प्रस्ताव वास्तव में एक अच्छा विचार लगता है, लेकिन उसमें कर्षण नहीं हो सकता है क्योंकि इसे लागू करना बहुत मुश्किल होगा, बहुत भ्रामक होगा, या पुराने कोड का खंडन करेगा।


यहां 2003 n1449 से एक पुराना पेपर है । औचित्य टेम्प्लेट से संबंधित प्रतीत होता है। चेतावनी: पीडीएफ से कॉपी करने के कारण टाइपो हो सकता है।

पहले एक खिलौना उदाहरण पर विचार करें:

template <typename T>
class MyAlloc {/*...*/};

template <typename T, class A>
class MyVector {/*...*/};

template <typename T>

struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage

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

template <typename T> void foo (Vec<T>::type&);

तो, वाक्य रचना कुछ बदसूरत है। हम बजाय नेस्टेड से बचना ::type चाहते हैं हम निम्नलिखित की तरह कुछ पसंद करेंगे:

template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage

ध्यान दें कि हम विशेष रूप से शब्द "टाइपडेफ टेम्पलेट" से बचते हैं और भ्रम से बचने में मदद करने के लिए जोड़ी "का उपयोग" और "=" शामिल नए सिंटैक्स को बढ़ाते हैं: हम यहां किसी भी प्रकार को परिभाषित नहीं कर रहे हैं, हम इसके लिए एक पर्यायवाची (यानी) पेश कर रहे हैं। टेम्पलेट मापदंडों को शामिल करते हुए टाइप-आईडी (यानी प्रकार की अभिव्यक्ति) का एक अमूर्तन। यदि टेम्पलेट पैरामीटर का उपयोग प्रकार की अभिव्यक्ति में कटौती करने योग्य संदर्भों में किया जाता है, तो जब भी टेम्पलेट-आईडी बनाने के लिए टेम्पलेट उपनाम का उपयोग किया जाता है, तो संबंधित टेम्पलेट मापदंडों के मूल्यों को घटाया जा सकता है - इस पर और अधिक का पालन करेंगे। किसी भी स्थिति में, यह संभव है कि जेनेरिक कार्यों को लिखा जाए, जो Vec<T>कि समर्पण के संदर्भ में काम करते हैं , और वाक्यविन्यास में भी सुधार होता है। उदाहरण के लिए हम फू को फिर से लिख सकते हैं:

template <typename T> void foo (Vec<T>&);

हम यहाँ रेखांकित करते हैं कि टेम्पलेट अलायस के प्रस्ताव के प्राथमिक कारणों में से एक यह था कि तर्क में कटौती और foo(p) सफल होने के लिए कॉल ।


अनुवर्ती कागज n1489 बताता है कि usingउपयोग करने के बजाय क्यों typedef:

यह सुझाव दिया गया है कि (टाइप करें) कीवर्ड टाइप का उपयोग करें - जैसा कि पेपर में किया गया है [4] - टेम्पलेट एलियास को पेश करने के लिए:

template<class T> 
    typedef std::vector<T, MyAllocator<T> > Vec;

उस नोटेशन में एक प्रकार का उपनाम पेश करने के लिए पहले से ज्ञात कीवर्ड का उपयोग करने का लाभ है। हालाँकि, यह कई असमानताओं को भी प्रदर्शित करता है जिनके बीच एक संदर्भ में टाइप-नाम के लिए उपनाम का परिचय देने के लिए ज्ञात कीवर्ड का उपयोग करने का भ्रम है जहां उपनाम किसी प्रकार को नामित नहीं करता है, लेकिन एक टेम्पलेट; Vecएक प्रकार के लिए एक उपनाम नहीं है, और एक टाइप-बीफ़-नाम के लिए नहीं लिया जाना चाहिए। नाम Vecपरिवार का एक नाम है std::vector< [bullet] , MyAllocator< [bullet] > > - जहां एक प्रकार के नाम के लिए बुलेट एक प्लेसहोल्डर है। नतीजतन हम "टाइपडेफ़" वाक्य रचना का प्रस्ताव नहीं करते हैं। दूसरी ओर सजा

template<class T>
    using Vec = std::vector<T, MyAllocator<T> >;

पढ़ा जा सकता है / के रूप में व्याख्या की: अब से, मैं के Vec<T>लिए एक पर्याय के रूप में उपयोग करेंगे std::vector<T, MyAllocator<T> >। उस पढ़ने के साथ, अलियासिंग का नया वाक्य-विन्यास यथोचित तार्किक लगता है।

मुझे लगता है कि महत्वपूर्ण अंतर यहां बनाया गया है, टाइप एस के बजाय उर्फ तों । उसी दस्तावेज़ से एक और उद्धरण:

एक उपनाम-घोषणा एक घोषणा है, और परिभाषा नहीं है। एक उपनाम- घोषणापत्र एक घोषणा क्षेत्र में एक नाम को घोषणा के दाईं ओर से नामित प्रकार के लिए एक उपनाम के रूप में पेश करता है। इस प्रस्ताव का मूल नाम उपनामों के साथ खुद को चिंतित करता है, लेकिन स्पष्ट रूप से नामकरण-अलियासिंग या ओवरलोड कार्यों के नामकरण सेट के वैकल्पिक वर्तनी प्रदान करने के लिए संकेतन को सामान्यीकृत किया जा सकता है (आगे की चर्चा के लिए for 2.3 देखें)। [ मेरा ध्यान दें: उस अनुभाग में चर्चा की गई है कि क्या वाक्यविन्यास ऐसा लग सकता है और कारणों से यह प्रस्ताव का हिस्सा नहीं है। ] यह ध्यान दिया जा सकता है कि व्याकरण उत्पादन अलियास-घोषणा कहीं भी स्वीकार्य है एक टाइपराइफ घोषणा या नाम स्थान-अलियास-परिभाषा स्वीकार्य है।

सारांश, की भूमिका के लिए using:

  • टेम्प्लेट एलियासेस (या टेम्प्लेट टाइप्स, पूर्व पसंद किया जाता है)
  • नाम स्थान उपनाम (यानी, namespace PO = boost::program_optionsऔर using PO = ...समतुल्य)
  • दस्तावेज़ कहता है A typedef declaration can be viewed as a special case of non-template alias-declaration। यह एक सौंदर्य परिवर्तन है, और इस मामले में समान माना जाता है।
  • कुछ को दायरे में लाना (उदाहरण के लिए, namespace stdवैश्विक दायरे में), सदस्य कार्य, निर्माणकर्ता को विरासत में देना

इसका उपयोग इसके लिए नहीं किया जा सकता है:

int i;
using r = i; // compile-error

इसके बजाय करें:

using r = decltype(i);

ओवरलोड का एक नामकरण।

// bring cos into scope
using std::cos;

// invalid syntax
using std::cos(double);

// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);

2
@ user3111311 आपके मन में अन्य कौन सा कीवर्ड था? "ऑटो"? "रजिस्टर करें"?
रेमंड चेन

2
using P = [](double)->void;AFAIK, मान्य C ++ 11 नहीं है। हालांकि यह है: using P = auto(double)->void;और एक फ़ंक्शन प्रकार (जैसे कि P*फ़ंक्शन पॉइंटर) का उत्पादन करता है ।
dyp


1
@ रेमंडचेन: वास्तव में registerयह बुरा नहीं लगेगा, इसमें है:register X as Y
MFH

1
दुर्भाग्य से registerएक चर घोषणा शुरू होती है इसलिए इसका पहले से ही एक अर्थ है। एक रजिस्टर चर को Y टाइप X का घोषित करें।
रेमंड चेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.