उपयोगकर्ता द्वारा परिभाषित शाब्दिक C ++ में कौन सी नई क्षमताएं हैं?


139

C ++ 11 उपयोगकर्ता परिभाषित शाब्दिक का परिचय देता है जो मौजूदा शाब्दिक के आधार पर नए शाब्दिक वाक्य रचना की शुरूआत की अनुमति देगा ( int, hex, string,float ) ताकि किसी भी प्रकार की एक शाब्दिक प्रस्तुति के लिए सक्षम हो जाएगा।

उदाहरण:

// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{ 
    return std::complex<long double>(0, d); 
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)

// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42

// std::string
std::string operator "" _s(const char* str, size_t /*length*/) 
{ 
    return std::string(str); 
}

auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

पहली नज़र में यह बहुत अच्छा लग रहा है, लेकिन मैं सोच रहा हूं कि यह वास्तव में कितना लागू होता है, जब मैंने प्रत्यय होने के बारे में सोचने की कोशिश की _ADऔर _BCतारीखें बनाईं तो मैंने पाया कि यह ऑपरेटर के आदेश के कारण समस्याग्रस्त है। 1974/01/06_ADपहले मूल्यांकन 1974/01करेंगे (सादे के रूप मेंint एस) और केवल बाद में 06_AD( 0ऑक्टेल कारणों के बिना लिखे जाने के लिए अगस्त और सितंबर के कुछ भी नहीं कहने के लिए)। यह सिंटैक्स होने के द्वारा चारों ओर काम किया जा सकता है1974-1/6_AD ताकि ऑपरेटर मूल्यांकन आदेश काम करे लेकिन यह क्लंकी है।

तो मेरा सवाल यह है कि क्या आपको लगता है कि यह सुविधा अपने आप को सही ठहराएगी? आप अपने सी + + कोड को और अधिक पठनीय बनाने के लिए किन अन्य शाब्दिकों को परिभाषित करना चाहेंगे?


अंतिम सिंटैक्स को जून 2011 में अंतिम प्रारूप में फिट करने के लिए अपडेट किया गया सिंटैक्स


8
मैं इसे बंद करने वाला हूं। शीर्षक काफी स्पष्ट रूप से स्फूर्त है।
पिल्ला

76
@DeadMG, अगर आपको कोई समस्या है, तो शीर्षक को आप इसे संपादित कर सकते हैं। यह एक 3 साल पुराने सवाल को बंद करने की कोशिश कर रहा है, जिसमें 11 अपवोट और 8 पसंदीदा हैं। (इस बात का उल्लेख नहीं है कि इस साइट पर पिछले 3 वर्षों में शिष्टाचार बदल गया है)।
मत्ती

5
मुझे लगता है कि आपको अपने उदाहरणों में त्रुटि है: string operator "" _s(const char*s);"पार्स करने के लिए उपयोग नहीं किया जा सकता है "hello"_s"। यह एक स्ट्रिंग शाब्दिक है और एक अतिरिक्त size_tपैरामीटर के साथ ऑपरेटर की तलाश करेगा । क्या मैं सही हू?
टावी

1
एक चीज जिसके बारे में मैंने सोचा है कि क्या यह C ++ में "पोर्टेबल सी" लिखने के लिए समझ में आएगा, uint16_tजिनके प्रकार व्यवहार की तरह कार्यान्वयन-निर्भर हैं, समान प्रकार uwrap16और unum16जिनके व्यवहार कार्यान्वयन-स्वतंत्र होंगे, जैसे कि uwrap16 w=1; unum16 n=1;भाव w-2और क्रमशः n-2पैदावार करेगा (uwrap16)65535और (int)-1[ uint16_tपहले सिस्टम पर पहला परिणाम देगा जहां int16 बिट्स है, और सिस्टम पर दूसरा जहां intबड़ा है]। मैंने जो सबसे बड़ी समस्या देखी, वह न्यूमेरिकल शाब्दिक थी।
सुपरकाट

1
संख्यात्मक परिभाषित करने में सक्षम होने के कारण अन्य परिभाषित-व्यवहार संख्यात्मक प्रकारों के साथ सुचारू रूप से अंतर्संबंधित होता है, ऐसा प्रतीत होता है कि इसे ऐसे प्रकारों को एक भाषा बनाने के लिए उपयोग करने की अनुमति होनी चाहिए जहां कोड जो कार्यान्वयन-निर्भर कार्यों को करना चाहते थे, कार्यान्वयन पर भरोसा किए बिना ऐसा कर सकते थे- परिभाषित व्यवहार। कुछ स्थान ऐसे हैं जहां IDB अभी भी अपरिहार्य है क्योंकि सूचक अंतर और sizeofकार्यान्वयन-निर्भर पूर्णांक प्रकारों की वापसी जैसी चीजें हैं , लेकिन स्थिति अभी भी इससे बहुत बेहतर बनाई जा सकती है। आप उस अवधारणा के बारे में क्या सोचेंगे?
सुपरकाट

जवाबों:


71

यहां एक ऐसा मामला है जहां एक निर्माता कॉल के बजाय उपयोगकर्ता द्वारा परिभाषित शाब्दिक का उपयोग करने का एक फायदा है:

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

लाभ यह है कि एक रन-टाइम अपवाद संकलन-टाइम त्रुटि में परिवर्तित हो जाता है। आप एक स्ट्रिंग लेने वाले बिटसेट ctor में स्टेटिक एसटर को नहीं जोड़ सकते हैं (कम से कम बिना स्ट्रिंग टेम्पलेट तर्क के)।


7
आप एक ही काम कर सकते हैं std :: बिटसेट को एक उचित बाधा निर्माणकर्ता।
निकोल बोलस

1
@NicolBolas तुम सही हो। मैं वास्तव में हैरान हूं कि कोई वहां नहीं है। हो सकता है कि 2014 के लिए हमें एक या दो प्रस्ताव देना चाहिए अगर इसमें बहुत देर नहीं हुई है।
एम्सआर

192

पहली नजर में यह साधारण सिन्थेटिक चीनी लगती है।

लेकिन जब हम गहराई से देखते हैं, तो हम इसे सिंटैक्टिक शुगर से अधिक देखते हैं, क्योंकि यह उपयोगकर्ता-परिभाषित प्रकार बनाने के लिए C ++ उपयोगकर्ता के विकल्पों का विस्तार करता है जो बिल्कुल अलग-अलग प्रकारों के समान व्यवहार करते हैं। इसमें, यह छोटा "बोनस" C ++ के अलावा एक बहुत ही दिलचस्प C ++ 11 है।

क्या हमें वास्तव में C ++ में इसकी आवश्यकता है?

पिछले वर्षों में मेरे द्वारा लिखे गए कोड में मुझे कुछ उपयोग दिखाई दे रहे हैं, लेकिन सिर्फ इसलिए कि मैंने इसे C ++ में उपयोग नहीं किया है, इसका मतलब यह नहीं है कि यह किसी अन्य C ++ डेवलपर के लिए दिलचस्प नहीं है

हमने C ++ (और C में, मुझे लगता है), संकलक-परिभाषित शाब्दिक का उपयोग किया था, पूर्णांक संख्याओं को लघु या दीर्घ पूर्णांक के रूप में टाइप करने के लिए, वास्तविक संख्या फ्लोट या डबल (या यहां तक ​​कि डबल डबल) के रूप में और सामान्य या चौड़े वर्णों के रूप में वर्ण तार। ।

C ++ में, हमारे पास अपने स्वयं के प्रकार (यानी कक्षाएं) बनाने की संभावना थी , संभावित रूप से ओवरहेड (इनलाइनिंग, आदि) नहीं। हमारे पास ऑपरेटरों को उनके प्रकारों से जोड़ने की संभावना थी, उनके साथ समान निर्मित प्रकारों का व्यवहार करने की, जो C ++ डेवलपर्स को स्वाभाविक रूप से मैट्रिसेस और जटिल संख्याओं का उपयोग करने में सक्षम बनाता है जैसे कि अगर उन्हें भाषा में जोड़ा गया हो। हम कास्ट ऑपरेटरों को भी जोड़ सकते हैं (जो आमतौर पर एक बुरा विचार है, लेकिन कभी-कभी, यह सिर्फ सही समाधान है)।

उपयोगकर्ता-प्रकारों को अंतर्निहित प्रकारों के रूप में व्यवहार करने के लिए हम अभी भी एक चीज से चूक गए: उपयोगकर्ता-परिभाषित शाब्दिक।

इसलिए, मुझे लगता है कि यह भाषा के लिए एक प्राकृतिक विकास है, लेकिन जितना संभव हो उतना पूरा होने के लिए: " यदि आप एक प्रकार बनाना चाहते हैं, और आप चाहते हैं कि यह बिल्ट-इन प्रकारों के रूप में अधिक से अधिक संभव हो, तो यहां उपकरण हैं। .. "

मुझे लगता है कि यह प्रत्येक आदिम को एक संरचना बनाने के लिए .NET के निर्णय के समान है, जिसमें बूलियन, पूर्णांक, आदि शामिल हैं, और सभी संरचनाएं ऑब्जेक्ट से प्राप्त होती हैं। यह निर्णय अकेले ही .NET को परे ले जाता है जब आदिम के साथ काम करते समय जावा की पहुंच से कोई फर्क नहीं पड़ता है कि जावा अपने विनिर्देश में कितना बॉक्सिंग / अनबॉक्सिंग हैक करेगा।

क्या आपको वास्तव में C ++ में इसकी आवश्यकता है?

यह प्रश्न आपको उत्तर देने के लिए है। ब्रजेन स्ट्रॉस्ट्रुप नहीं। हर्ब सटर नहीं। जो भी C ++ मानक समिति का सदस्य नहीं है। यही कारण है कि आपके पास C ++ में विकल्प है , और वे अकेले निर्मित प्रकारों के लिए एक उपयोगी अंकन को प्रतिबंधित नहीं करेंगे।

यदि आपको इसकी आवश्यकता है, तो यह एक स्वागत योग्य है। अगर तुम नहीं, अच्छी तरह से ... यह प्रयोग नहीं करते। इसमें आपका कुछ भी खर्च नहीं होगा।

C ++ में आपका स्वागत है, वह भाषा जहाँ सुविधाएँ वैकल्पिक हैं।

फूला हुआ ??? मुझे अपने परिसरों दिखाओ !!!

फूला हुआ और जटिल (सजा का इरादा) के बीच अंतर है।

जैसे नील्स द्वारा दिखाया गया है कि उपयोगकर्ता-परिभाषित शाब्दिक C ++ में कौन सी नई क्षमताएं हैं? , एक जटिल संख्या लिखने में सक्षम होने के कारण C और C ++ में "हाल ही में" जोड़े गए दो विशेषताओं में से एक है:

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

अब, ऑपरेटर ओवरलोडिंग का उपयोग करते हुए, C99 "डबल कॉम्प्लेक्स" टाइप और C ++ "std :: कॉम्प्लेक्स" दोनों प्रकारों को गुणा, जोड़ा, घटाया आदि किया जा सकता है।

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

C ++ में, उन्होंने भाषा की मौजूदा विशेषताओं का उपयोग किया, यह देखा कि शाब्दिक विशेषता भाषा का एक प्राकृतिक विकास था, और इस तरह इसे जोड़ा गया।

सी में, यदि आपको किसी अन्य प्रकार के लिए समान नोटिफिकेशन एन्हांसमेंट की आवश्यकता है, तो आप अपने क्वांटम वेव फ़ंक्शंस (या 3 डी पॉइंट्स, या जो भी बेसिक प्रकार आप अपने कार्य क्षेत्र में उपयोग कर रहे हैं) को जोड़ने के लिए अपनी पैरवी तक किस्मत से बाहर हैं। एक निर्मित प्रकार के रूप में सी मानक सफल होता है।

C ++ 11 में, आप इसे स्वयं कर सकते हैं:

Point p = 25_x + 13_y + 3_z ; // 3D point

क्या यह फूला हुआ है? नहीं , आवश्यकता है, जैसा कि दिखाया गया है कि कैसे C और C ++ कॉम्प्लेक्स दोनों को अपने शाब्दिक जटिल मूल्यों का प्रतिनिधित्व करने का एक तरीका चाहिए।

क्या यह गलत तरीके से डिजाइन किया गया है? नहीं , इसे हर दूसरे C ++ फीचर के रूप में डिज़ाइन किया गया है, जिसमें मन में विस्तार है।

क्या यह केवल संकेतन प्रयोजनों के लिए है? नहीं , क्योंकि यह आपके कोड में टाइप सुरक्षा भी जोड़ सकता है।

उदाहरण के लिए, आइए एक CSS उन्मुख कोड की कल्पना करें:

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

मूल्यों के असाइनमेंट के लिए एक मजबूत टाइपिंग लागू करना बहुत आसान है।

खतरनाक है?

अच्छा प्रश्न। क्या इन कार्यों को नाम दिया जा सकता है? यदि हाँ, तो जैकपॉट!

वैसे भी, सब कुछ की तरह, आप खुद को मार सकते हैं यदि किसी उपकरण का अनुचित तरीके से उपयोग किया जाता है । सी शक्तिशाली है, और यदि आप सी बंदूक का दुरुपयोग करते हैं, तो आप अपने सिर को गोली मार सकते हैं। C ++ में C गन है, लेकिन स्केलपेल, टेसर और जो भी अन्य टूल आपको टूलकिट में मिलेगा। आप स्केलपेल का दुरुपयोग कर सकते हैं और खुद को मौत के घाट उतार सकते हैं। या आप बहुत ही सुंदर और मजबूत कोड बना सकते हैं।

तो, हर C ++ फीचर की तरह, क्या आपको वास्तव में इसकी आवश्यकता है? यह वह प्रश्न है जिसका उत्तर आपको C ++ में उपयोग करने से पहले देना चाहिए। यदि आप नहीं करते हैं, तो यह आपको कुछ भी खर्च नहीं करेगा। लेकिन अगर आपको वास्तव में इसकी आवश्यकता है, तो कम से कम, भाषा आपको निराश नहीं करेगी।

तारीख का उदाहरण?

आपकी त्रुटि, यह मुझे लगता है, यह है कि आप ऑपरेटरों को मिला रहे हैं:

1974/01/06AD
    ^  ^  ^

इसे टाला नहीं जा सकता, क्योंकि / एक ऑपरेटर होने के नाते, संकलक को इसकी व्याख्या करनी होगी। और, AFAIK, यह एक अच्छी बात है।

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

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

व्यक्तिगत रूप से, मैं पूर्णांक और आईएसओ तिथियां चुनूंगा, लेकिन यह आपकी आवश्यकताओं पर निर्भर करता है। उपयोगकर्ता को अपने शाब्दिक नामों को परिभाषित करने देने का पूरा बिंदु कौन सा है।


1
धन्यवाद, मुझे और मेरी अन्य वैकल्पिक व्यक्तित्वों की खोज हुई। अधिक गंभीरता से, मैंने इसे अकेले लिखा था, लेकिन शायद मैं अपनी मूल भाषा की कुछ अभिव्यक्ति का उपयोग कर रहा हूं और वे अंग्रेजी में अच्छी तरह से अनुवाद नहीं करते हैं।
21

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

3
+1। वास्तव में अच्छी व्याख्या। हम इसके लागू होने का इंतजार कर रहे हैं। यह वास्तव में हमारे लिए महत्वपूर्ण है। हम MDE (मॉडल-चालित इंजीनियरिंग) पर काम करते हैं और इसे एक उपयुक्तता पाते हैं। हम अपना मामला समझाने के लिए नीचे एक प्रतिक्रिया जोड़ रहे हैं।
डिएगो सेविला

9
@TGV:: you can write 1+2i, but you still can't write a+bi, so there's absolutely no pointयहां तक ​​कि आपके a+biउदाहरण को अनदेखा करना हास्यास्पद है, आप इसे "कम आवृत्ति" के रूप में अनुभव करते हैं इसका मतलब यह नहीं है कि हर कोई करता है। । । बड़ी तस्वीर को देखते हुए, बिंदु यह सुनिश्चित करने के लिए है कि उपयोगकर्ता-परिभाषित ऑब्जेक्ट भाषा के प्रथम श्रेणी के नागरिकों के रूप में जितना संभव हो उतना संभव हो सकता है, जैसा कि बिल्ड-इन प्रकार हैं। तो, अगर आप लिख सकते हैं 1.5fऔर 1000UL, आप क्यों नहीं लिख सकते हैं 25iया यहां तक ​​कि 100101b? C और Java के विपरीत, उपयोगकर्ता प्रकारों को C ++ में भाषा का द्वितीय श्रेणी का नागरिक नहीं माना जाता है।
पियरसबल

3
@ एटन:: Most of data still comes from IOकोड में बहुत अधिक हार्डकोड मान हैं। सभी बूलियन्स, सभी पूर्णांक, सभी डबल्स को देखें जो कोड में आते हैं, क्योंकि यह लिखने के लिए अधिक सुविधाजनक है कि x = 2 * y ;इसके बजाय एक दृढ़ता से टाइप किया गया स्थिरांक x = Two * yकहां Twoहै । उपयोगकर्ता परिभाषित शाब्दिक हमें इस पर एक प्रकार लगाने में सक्षम बनाता है, और लिखता है: और संकलक सत्यापित करता है कि गणना समझ में आती है। । । यह सब मजबूत टाइपिंग के बारे में आता है। । । शायद आप इसका उपयोग नहीं करेंगे। लेकिन मुझे यकीन है, जैसे ही मैं काम पर एक C ++ 11 सक्षम संकलक का उपयोग कर सकूंगा। x = 2_speed * y ;
पियरसबल

36

यह गणितीय कोड के लिए बहुत अच्छा है। मेरे दिमाग से मैं निम्नलिखित ऑपरेटरों के लिए उपयोग देख सकता हूं:

डिग्री के लिए गिरावट। यह लिखने के कोण को अधिक सहज बनाता है।

double operator ""_deg(long double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

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

int operator ""_fix(long double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

ये कैसे उपयोग करने के लिए अच्छे उदाहरण की तरह लग रहे हैं। वे कोड को अधिक पठनीय बनाने में मदद करते हैं। यह कोड को अपठनीय बनाने के लिए एक और उपकरण है, लेकिन हमारे पास पहले से ही बहुत सारे उपकरण हैं जो एक से अधिक दुरुपयोग करते हैं।


1
"लेकिन हमारे पास पहले से ही बहुत सारे उपकरण दुरुपयोग हैं जो एक और अधिक चोट नहीं पहुंचाता है। " वाह, मुझे उम्मीद है कि इन सभी के पीछे दर्शन नहीं है कि c ++ [x] 1234567890 हाल ही में बाढ़ आ गई है। एक पुस्तकालय सीखने की कल्पना कीजिए जो उन सभी का उपयोग करता है, साथ ही कॉन्फ़िगरेशन के लिए दस फ़ाइल प्रारूप और आपके कोड के पूर्व और बाद के प्रसंस्करण के लिए दो उपकरण ...
मास्टरएक्सिलो

@मास्टरएक्सिलो, वास्तव में, आपका उदाहरण बेतुका है: यूडीएल को कार्यों की तुलना में सीखना अधिक कठिन नहीं है, क्योंकि उनके लिए सिर्फ सिंटैक्स चीनी - और इसके अलावा, कोई भी अच्छा केवल यूएक्स को बेहतर बनाने के लिए आवश्यक सुविधाओं का उपयोग करता है - और दस्तावेजों में यह क्या है सबका मतलब। यदि कोई अपठनीय कोड जनरेट करने के लिए किसी सुविधा का उपयोग करता है (यह मानते हुए कि उसके काम की लाइन में सभी परिहार्य ...), तो यह उस सुविधा को दोष नहीं देता है, बस उपयोग। इसके अलावा, एक व्यक्ति का अपठनीय दूसरे की रोटी और मक्खन है। यह सभी राय है - और विकल्प । यदि आप उन्हें पसंद नहीं करते हैं, तो चिंता न करें! आपको उनका उपयोग नहीं करना है। दूसरे कर सकते हैं
अंडरस्कोर_ड

17

UDLs नामांकित हैं (और घोषणाओं / निर्देशों का उपयोग करके आयात किया जा सकता है, लेकिन आप स्पष्ट रूप से नाम-पत्र जैसे शाब्दिक नाम नहीं दे सकते हैं 3.14std::i), जिसका अर्थ है वहाँ (उम्मीद है) एक टन की झड़प नहीं होगी।

तथ्य यह है कि वे वास्तव में templated किया जा सकता है (और constexpr'd) का मतलब है कि आप UDLs के साथ कुछ बहुत शक्तिशाली सामान कर सकते हैं। बिगिंट लेखक वास्तव में खुश होंगे, क्योंकि वे अंत में मनमाने ढंग से बड़े स्थिरांक हो सकते हैं, जो संकलन समय (कॉन्स्ट्रेक्स या टेम्प्लेट के माध्यम से) में गणना करते हैं।

मुझे बस इस बात का दुःख है कि हम काल्पनिक इकाई के sलिए std::stringऔर उसके समान मानक में कुछ उपयोगी शाब्दिक नहीं देखेंगे i

यूडीएल द्वारा सहेजे जाने वाले कोडिंग समय की मात्रा वास्तव में उच्च नहीं है, लेकिन पठनीयता में काफी वृद्धि होगी और अधिक से अधिक गणना तेजी से निष्पादन के लिए संकलन-समय में स्थानांतरित की जा सकती है।


नाम स्थान के बारे में बात साफ करने के लिए धन्यवाद ... मैं सोच रहा था कि।
नातान रीड

12

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

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

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

होवर, यह पता चला है कि एक मॉडल या मेटामॉडल में प्रत्येक तत्व, आमतौर पर एक नाम है। हम लिखना चाहेंगे:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

लेकिन, C ++, और न ही C ++ 0x इसे अनुमति नहीं देते हैं, क्योंकि तार टेम्प्लेट के तर्क के रूप में निषिद्ध हैं। आप नाम चार वर्ण से लिख सकते हैं, लेकिन यह एक गड़बड़ है। उचित उपयोगकर्ता-परिभाषित शाब्दिक के साथ, हम कुछ ऐसा ही लिख सकते हैं। मान लें कि हम "_n" का उपयोग मॉडल तत्व नामों की पहचान करने के लिए करते हैं (मैं सटीक सिंटैक्स का उपयोग नहीं करता, सिर्फ एक विचार बनाने के लिए):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

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


4
मुझे बहुत पसंद है by the compiler at compile timeभाग ... :-)
परसब्बल

12

Bjarne Stroustrup इस C ++ 11 में UDL के बारे में बात करता है , पहले भाग में, टाइप-रिच इंटरफेस पर, लगभग 20 मिनट का निशान।

UDLs के लिए उनका मूल तर्क एक समाजवाद का रूप लेता है:

  1. "ट्रिवियल" प्रकार, अर्थात्, अंतर्निहित आदिम प्रकार, केवल तुच्छ प्रकार की त्रुटियों को पकड़ सकते हैं। समृद्ध प्रकार के साथ इंटरफेस प्रकार प्रणाली को अधिक प्रकार की त्रुटियों को पकड़ने की अनुमति देते हैं।

  2. प्रकार की त्रुटियां जो बड़े पैमाने पर टाइप कोड को पकड़ सकती हैं, वास्तविक कोड पर प्रभाव डाल सकती हैं। (वह मार्स क्लाइमेट ऑर्बिटर का उदाहरण देता है, जो एक महत्वपूर्ण स्थिरांक में एक आयाम त्रुटि के कारण बदनाम हुआ)।

  3. वास्तविक कोड में, इकाइयों का उपयोग शायद ही कभी किया जाता है। लोग उनका उपयोग नहीं करते हैं, क्योंकि अमीर प्रकार बनाने के लिए रनटाइम कंप्यूट या मेमोरी ओवरहेड को लगाना बहुत महंगा पड़ता है, और पहले से मौजूद C ++ टेम्प्लेटेड यूनिट कोड का उपयोग करना इतना कुख्यात है कि कोई भी इसका उपयोग नहीं करता है। (जाहिर है, कोई भी इसका उपयोग नहीं करता है, भले ही पुस्तकालय एक दशक के आसपास रहे हों)।

  4. इसलिए, वास्तविक कोड में इकाइयों का उपयोग करने के लिए इंजीनियरों को प्राप्त करने के लिए, हमें एक ऐसे उपकरण की आवश्यकता थी जो (1) कोई रनटाइम ओवरहेड न हो और (2) तर्कसंगत रूप से स्वीकार्य हो।


9

संकलन-समय आयाम की जाँच का समर्थन करना एकमात्र औचित्य है।

auto force = 2_N; 
auto dx = 2_m; 
auto energy = force * dx; 

assert(energy == 4_J); 

उदाहरण के लिए देखें PhysUnits-CT-Cpp11 , एक छोटा C ++ 11, C ++ 14 हेडर-केवल लाइब्रेरी जो संकलन-समय आयामी विश्लेषण और यूनिट / मात्रा हेरफेर और रूपांतरण के लिए है। Boost.Units की तुलना में सरल , मी, जी, एस, मीट्रिक उपसर्गों जैसे मी, के, एम, जैसे यूनिट प्रतीक शाब्दिकों का समर्थन करता है , केवल मानक C ++ पुस्तकालय, SI- केवल, आयामों की अभिन्न शक्तियों पर निर्भर करता है।


या निक होल्टहॉस द्वारा कोई निर्भरता के साथ c ++ 14 पर निर्मित इकाइयां , एक संकलन-समय, शीर्षलेख-केवल, आयामी विश्लेषण और इकाई रूपांतरण लाइब्रेरी देखें ।
मार्टिन मोएने

6

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

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... मुझे आश्चर्य है कि आप आज कैसे व्यक्त करेंगे। आपके पास एक KG और एक LB वर्ग होगा और आप अंतर्निहित वस्तुओं की तुलना करेंगे:

assert(KG(1.0f) == LB(2.2f));

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

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

अंतत: यह सिंटैक्टिक शुगर होने वाला है, लेकिन पठनीयता पर इसका थोड़ा प्रभाव पड़ेगा। और शायद कुछ अभिव्यक्तियों को लिखना भी आसान होगा (पाप (180.0gg) पाप की तुलना में लिखना आसान है) (गिरावट (180.0)) और फिर ऐसे लोग होंगे जो अवधारणा का दुरुपयोग करते हैं। लेकिन फिर, भाषा-अपमानजनक लोगों का उपयोग करना चाहिए। C + + के रूप में अभिव्यंजक के रूप में कुछ के बजाय बहुत प्रतिबंधात्मक भाषाएं।

आह, मेरी पोस्ट मूल रूप से कुछ भी नहीं कहती है सिवाय इसके: यह ठीक है, प्रभाव बहुत बड़ा नहीं होगा। चलो कोई बात नहीं। :-)


5
आपके कोष्ठक असंतुलित हैं! क्षमा करें, मेरा ओसीडी मुझसे भी नफरत करता है।
X-Istence

3

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


मैं पुष्टि करता हूं: बहुत दिलचस्प लेख।
पियरसबल

2

C ++ आमतौर पर उपयोग किए जाने वाले सिंटैक्स के बारे में बहुत सख्त है - प्रीप्रोसेसर को छोड़कर वहाँ बहुत अधिक नहीं है जो आप कस्टम सिंटैक्स / व्याकरण को परिभाषित करने के लिए उपयोग कर सकते हैं। उदाहरण के लिए, हम मौजूदा ऑपरैटोस को ओवरलोड कर सकते हैं, लेकिन हम नए को परिभाषित नहीं कर सकते हैं - IMO यह C ++ की भावना के साथ बहुत अधिक है।

मुझे अधिक अनुकूलित स्रोत कोड के लिए कुछ तरीके से कोई आपत्ति नहीं है - लेकिन चुना गया बिंदु मुझे बहुत अलग लगता है, जो मुझे सबसे अधिक भ्रमित करता है।

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

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

मैं "ऑटो" के संयोजन में कुछ योग्यता देखता हूं, एक यूनिट लाइब्रेरी जैसे कि बूस्ट यूनिट्स के साथ संयोजन में , लेकिन इस विज्ञापन को योग्यता देने के लिए पर्याप्त नहीं है।

हालांकि, मुझे आश्चर्य है कि हम किस चतुर विचार के साथ आते हैं।


1
using single letters in global namespace will probably be considered bad practiceलेकिन इसकी कोई प्रासंगिकता नहीं है: (ए) यूडीएल को (गैर-वैश्विक) नेमस्पेस दायरे में परिभाषित किया जाना चाहिए ... संभवत: क्योंकि (बी) उन्हें एक अंडरस्कोर से युक्त होना चाहिए> = 1 अक्षर, न केवल पत्र और अन्य पहचानकर्ता वैश्विक एनएस कार्यान्वयन के लिए आरक्षित हैं। इस विचार के खिलाफ कम से कम 2 बिंदु हैं कि यूडीएल सहज रूप से भ्रम पैदा करता है। जैसे ही नामस्थान की सुविधा की उपयोगिता को कम करने की गुंजाइश है, इसीलिए जैसे कि stdlib उन्हें घोषणा करता है inline namespaceकि उपयोगकर्ता थोक आयात कर सकते हैं यदि वांछित है।
अंडरस्कोर_ड

2

मैंने इस तरह बाइनरी स्ट्रिंग्स के लिए उपयोगकर्ता शाब्दिक का उपयोग किया:

 "asd\0\0\0\1"_b

std::string(str, n)कंस्ट्रक्टर का उपयोग \0करना ताकि स्ट्रिंग को आधे में कटौती न करें। (परियोजना विभिन्न फ़ाइल स्वरूपों के साथ बहुत काम करती है।)

यह तब भी मददगार था जब मैंने std::stringएक रैपर के पक्ष में भोजन किया std::vector


-5

उस चीज़ में लाइन का शोर बहुत बड़ा है। यह भी पढ़ने के लिए भयानक है।

मुझे पता है, क्या वे किसी भी तरह के उदाहरणों के साथ नए वाक्यविन्यास को जोड़ते हैं? उदाहरण के लिए, क्या उनके पास कुछ प्रोग्राम हैं जो पहले से ही C ++ 0x का उपयोग करते हैं?

मेरे लिए, यह हिस्सा:

auto val = 3.14_i

इस भाग का औचित्य नहीं है:

std::complex<double> operator ""_i(long double d) // cooked form
{ 
    return std::complex(0, d);
}

यहां तक ​​कि अगर आप 1000 अन्य लाइनों में भी आई-सिंटैक्स का उपयोग नहीं करेंगे। यदि आप लिखते हैं, तो आप संभवतः किसी और चीज़ की 10000 पंक्तियाँ भी लिखते हैं। खासकर जब आप अभी भी ज्यादातर हर जगह यह लिखेंगे:

std::complex<double> val = 3.14i

'ऑटो' -कॉवर्ड उचित हो सकता है, केवल शायद। लेकिन यह सिर्फ C ++ को लेने देता है, क्योंकि यह इस पहलू में C ++ 0x से बेहतर है।

std::complex<double> val = std::complex(0, 3.14);

यह ऐसा है .. जो सरल है। यहां तक ​​कि सोचा कि सभी एसटीडी और नुकीले कोष्ठक सिर्फ लंगड़े हैं यदि आप इसका उपयोग हर जगह करते हैं। मैं यह अनुमान लगाना शुरू नहीं करता कि एसटीडी 0 सीएक्स को चालू करने के लिए वाक्यविन्यास क्या है :: जटिल के तहत जटिल।

complex = std::complex<double>;

यह शायद कुछ सीधा है, लेकिन मुझे नहीं लगता कि यह C ++ 0x में इतना आसान है।

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

शायद? > :)

वैसे भी, बिंदु यह है: एसटीडी के बजाय 3.14i लिखना :: कॉम्प्लेक्स (0, 3.14); कुछ सुपर विशेष मामलों को छोड़कर आपको समग्र रूप से ज्यादा समय नहीं बचाता है।


10
@Cheery: आपके लिए, "ऑटो वैल = 3.14i" इसका समर्थन करने के लिए लिखे गए कोड को सही नहीं ठहराता है। मैं जवाब दे सकता था कि, मेरे लिए "printf ("% i ", 25)" प्रिंटफ के लिए लिखे गए कोड को सही नहीं ठहराता। क्या आप एक पैटर्न देखते हैं?
पियरसबल

5
@Cheery: "उस चीज़ में लाइन शोर बहुत बड़ा है"। नहीं, यह नहीं है ... "इसके अलावा यह पढ़ने के लिए भयानक है"। आपका व्यक्तिपरक तर्क दिलचस्प है, लेकिन आपको सामान्य रूप से कोड ओवरलोडिंग करने वाले ऑपरेटर पर एक नज़र
डालनी चाहिए

3
ऑटो पठनीयता में मदद करेगा। एक लूप में इंटरट्रेटर्स का उपयोग करने पर विचार करें: के लिए (ऑटो इट = वेजबिन (); यह? = वीनोएड (); ++ यह) ... मैं for_each के बारे में जानता हूं, लेकिन इसे इस्तेमाल करने के लिए एक फ़नकार बनाने के लिए नापसंद है। ।
KitsuneYMG

1
@kts: C ++ 1x के साथ हमारे पास लंबोदा और रेंज होगी
जो डी

3
यदि आपकी C ++ की लाइन C ++ 0x से बेहतर है, तो मेरी लाइन अभी तक बेहतर है। बस लिखें std::complex<double> val(0, 3.14);:।
बेन Voigt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.