2012-04-21 9 views
35

सी ++ 11 में टुपल्स का उपयोग करने के लिए अच्छे उपयोग-मामले क्या हैं? उदाहरण के लिए, मैं एक समारोह है कि एक स्थानीय struct को परिभाषित करता है इस प्रकार है:सी ++ 11 में टुपल्स के लिए अच्छे उपयोग-मामले क्या हैं?

template<typename T, typename CmpF, typename LessF> 
void mwquicksort(T *pT, int nitem, const int M, CmpF cmp, LessF less) 
{ 
    struct SI 
    { 
    int l, r, w; 
    SI() {} 
    SI(int _l, int _r, int _w) : l(_l), r(_r), w(_w) {} 
    } stack[40]; 

    // etc 

मैं एक std::tuple<int,int,int> है, जो सुविधाजनक निर्माणकर्ता और ऑपरेटरों को पहले से ही पूर्वनिर्धारित के साथ एक दूर छोटे घोषणा है साथ SI struct को बदलने के लिए विचार कर रहा था, लेकिन साथ निम्नलिखित नुकसान:

  • ट्यूपल तत्व अस्पष्ट, कार्यान्वयन-परिभाषित structs में छिपे हुए हैं। भले ही विजुअल स्टूडियो उनकी सामग्री को अच्छी तरह से व्याख्या करता है और दिखाता है, फिर भी मैं सशर्त ब्रेकपॉइंट्स नहीं डाल सकता जो ट्यूपल तत्वों के मूल्य पर निर्भर करता है।
  • व्यक्तिगत ट्यूपल फ़ील्ड (get<0>(some_tuple)) तक पहुंचने से संरचना तत्वों (s.l) तक पहुंचने से कहीं अधिक वर्बोज़ है।
  • नाम से फ़ील्ड तक पहुंचने से संख्यात्मक सूचकांक की तुलना में कहीं अधिक जानकारीपूर्ण (और छोटा!) है।

पिछले दो बिंदुओं को कुछ हद तक tie फ़ंक्शन द्वारा संबोधित किया गया है। इन नुकसानों को देखते हुए, ट्यूपल्स के लिए एक अच्छा उपयोग-मामला क्या होगा?

अद्यतन बाहर कर देता है कि VS2010 SP1 डीबगर निम्नलिखित सरणी std::tuple<int, int, int> stack[40] की सामग्री को नहीं दिखा सकते हैं, लेकिन यह ठीक काम करता है जब यह एक struct के साथ कोडित है। तो निर्णय मूल रूप से एक ब्रेनर है: यदि आपको कभी भी अपने मूल्यों का निरीक्षण करना होगा, तो एक स्ट्रक्चर का उपयोग करें [esp। जीडीबी जैसे डीबगर्स के साथ महत्वपूर्ण]।

+3

इंडेक्सिंग समस्या को उचित परिभाषित कॉन्स/एनम्स के साथ हल किया जा सकता है। – KillianDS

+2

आपने एक प्रकार का फ़ंक्शन लिखा है जो 'टी *, आकार' लेता है? लोलवॉट, आप कभी ऐसा क्यों करेंगे? – Puppy

+0

@DeadMG बस इतना है कि मैं आपको ट्रॉलिंग के लिए कुछ सामग्री दे सकता हूं। – zvrba

उत्तर

24

ठीक है, imho, सबसे महत्वपूर्ण हिस्सा सामान्य कोड है:

std::tuple<int,int> fun(); 

परिणाम मूल्यों सुंदर ढंग से इस प्रकार के रूप में इस्तेमाल किया जा सकता है। जेनेरिक कोड लिखना जो सभी प्रकार के structs पर काम करता है, जेनिक्स लिखने से बहुत कठिन है जो टुपल्स पर काम करता है। उदाहरण के लिए, std::tie फ़ंक्शन जिसे आपने स्वयं बताया है, वह structs के लिए बनाना लगभग असंभव होगा।

यह आप इस तरह काम करने के लिए अनुमति देता है:

  • देरी निष्पादन के लिए स्टोर समारोह मापदंडों (जैसे this question)
  • वापसी से अधिक पैरामीटर बोझिल बिना (अन) std::tie
  • साथ पैकिंग कम्बाइन (बराबर नहीं टाइप किया गया) डेटा सेट (उदाहरण के लिए समानांतर निष्पादन से), इसे std::tuple_cat के रूप में किया जा सकता है।

बात यह है कि यह इन उपयोगों के साथ नहीं रुकती है, लोग इस सूची में विस्तार कर सकते हैं और ट्यूबल के आधार पर जेनेरिक कार्यक्षमता लिख ​​सकते हैं जो structs के साथ करना कठिन है। कौन जानता है, शायद कल किसी को धारावाहिक उद्देश्यों के लिए एक शानदार उपयोग मिल जाएगा।

+1

उत्तर के रूप में चिह्नित किया गया है क्योंकि आपने मुझे 'tuple_cat' के बारे में अवगत कराया है, जिसे वीएस -2010 के लिए एमएसडीएन में सूचीबद्ध नहीं किया गया था। लेकिन आप किसी ऐसे फ़ंक्शन का रिटर्न वैल्यू कैसे घोषित करेंगे जो कुछ tuples 'x' और' y' के लिए 'tuple_cat (x, y) 'देता है जिसका प्रकार * फ़ंक्शन तर्क से आसानी से deducible नहीं है? – zvrba

+0

मुझे ट्यूपल के लिए आपके पहले उपयोग के मामले में रूचि है, क्या टुपल का उपयोग करने के बजाय 'std :: bind' का उपयोग करके फ़ंक्शन पैरामीटर को स्टोर करना आसान नहीं होगा? यह आपके द्वारा लिंक किए गए प्रश्न पर पूछा गया था लेकिन जवाब सिर्फ इतना था कि कोई और उन्हें टुपल दे रहा था। –

1

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

+3

@zvrba: यह "संकलन" समय इंटरऑप है, रनटाइम इंटरऑप भी संभव है।इसके अलावा, एक और भाषा सी ++ इंटरफेस का उपयोग कर सकती है। मैं शर्त लगाता हूं कि 'boost.python' जैसी चीज़ों से इसका फायदा हो सकता है। – KillianDS

+2

@zvrba: सी ++ .NET, पायथन, लुआ, रूबी, पर्ल, फोरट्रान इत्यादि के साथ इंटरऑपरेट करता है। यहां इंटरऑपरेट का मतलब है कि लिंक जोड़ने और कॉल करने में सक्षम होना ... और यदि आप बूस्ट पायथन, लुबाइंड जैसे गोंद पुस्तकालय लिखने जा रहे हैं , आरसीपीपी, इत्यादि, इंटरपॉप को यथासंभव निर्बाध के रूप में प्रकट करने के लिए भाषा शब्दावली के हिस्से के रूप में उपलब्ध टुपल्स जैसी सुविधाएं अच्छी लगती हैं। –

+1

@ जोहानज़विन "इंटरऑपरेट" का मतलब है कि मुझे गोंद परतों को लिखे बिना अन्य भाषाओं में फ़ंक्शंस कॉल करना है। तो इसमें सी, सी ++, और फोरट्रान शामिल हैं, जिन्हें मैं भूल गया हूं। लेकिन मैं मानता हूं कि टुपल्स रखना अच्छा होता है जो "अन्य भाषा के" एपीआई को अधिक बारीकी से मिरर करने की अनुमति देता है। – zvrba

54

यह फ़ंक्शन से कई मान वापस करने का एक आसान तरीका है;

int a; 
int b; 
std::tie(a,b)=fun(); 
+0

आप 'ऑटो' का उपयोग नहीं कर सकते हैं। आप कॉपी कन्स्ट्रक्टर का उपयोग नहीं कर सकते (और इसलिए _RVO_ का उपयोग नहीं कर सकते हैं)। यदि 'std :: tie (auto a, auto b) = fun() लिखना संभव था, तो यह समझ में आएगा। आप 'ऑटो tuple = func();' टाइप कर सकते हैं और फिर 'std :: <0> (tuple) प्राप्त करें;' और 'std :: <1> (tuple) प्राप्त करें; 'लेकिन यह भयानक है। –

12

क्या आपने कभी std::pair का उपयोग किया है? std::tuple का उपयोग करने वाले कई स्थान समान हैं, लेकिन बिल्कुल दो मानों तक सीमित नहीं हैं।

नुकसान आप tuples के लिए सूची भी std पर लागू होते हैं :: जोड़ी, कभी कभी आप first और second से अपने सदस्यों के लिए बेहतर नाम के साथ एक अधिक अर्थपूर्ण प्रकार चाहते हैं, लेकिन कभी-कभी आपको लगता है कि जरूरत नहीं है। यह tuples पर लागू होता है।

9

मुझे लगता है कि कुछ सामान्य पुस्तकालय सुविधा के कार्यान्वयन विवरण के बाहर tuples के लिए कोई अच्छा उपयोग नहीं है।

टाइपिंग में (संभव) बचत परिणामस्वरूप कोड के स्वयं-दस्तावेज गुणों में हानियों को ऑफ़सेट नहीं करती है।

structs के लिए tuples को रोकना जो सिर्फ एक फ़ील्ड के लिए सार्थक नाम लेता है, फ़ील्ड नाम को "संख्या" के साथ बदलता है (बस एक std :: pair की दुर्भाग्यपूर्ण अवधारणा की तरह)।

टुपल्स का उपयोग करके एकाधिक मानों को लौटाना बहुत कम आत्म-दस्तावेज है तो विकल्प - नामित प्रकारों को लौटाना या नामित संदर्भों का उपयोग करना। इस स्व-दस्तावेज के बिना, यदि वे पारस्परिक रूप से परिवर्तनीय हैं, तो लौटाए गए मूल्यों के आदेश को भ्रमित करना आसान है।

+0

ऑर्डर द्वारा तर्क पास करना टुपल का उपयोग करके एकाधिक मानों को वापस करने से कहीं ज्यादा बेहतर नहीं है। आप अभी भी पैरामीटर के आदेश को भ्रमित कर सकते हैं। लेकिन कम से कम प्रत्येक पैरामीटर का अपना नाम होता है। टुपल के मूल्य नहीं हैं। –

18

मुझे लगता है कि tuple रों के लिए सबसे अधिक उपयोग std::tie से आता है:

bool MyStruct::operator<(MyStruct const &o) const 
{ 
    return std::tie(a, b, c) < std::tie(o.a, o.b, o.c); 
} 
जवाब यहां के कई अन्य उदाहरण के साथ साथ

। मुझे यह उदाहरण सबसे अधिक उपयोगी होने के लिए मिलता है, हालांकि, यह सी ++ 03 में कैसे उपयोग किया जाता है, इस बारे में बहुत से प्रयासों को बचाता है।

+0

हाँ, मैंने अभी इस बारे में पता लगाया और इसका उपयोग किया। मैंने थोड़ी अधिक विस्तृत/जेनेरिक विधि का उपयोग किया, जिसे मैं दूसरे जवाब में निकाल सकता हूं। –

6

वास्तविक उपयोग के मामले ऐसे परिस्थितियां हैं जहां आपके पास असामान्य तत्व हैं- विविध टेम्पलेट्स और लैम्ब्डा फ़ंक्शंस। दोनों स्थितियों में आप अज्ञात प्रकारों के साथ अज्ञात तत्वों को प्राप्त कर सकते हैं और इस प्रकार उन्हें स्टोर करने का एकमात्र तरीका अज्ञात तत्वों के साथ एक संरचना है: std :: tuple। हर दूसरी परिस्थिति में आपके पास ज्ञात प्रकार के नाम-सक्षम तत्व हैं और इस प्रकार एक सामान्य संरचना का उपयोग कर सकते हैं, जो कि 99% समय का बेहतर उत्तर है।

उदाहरण के लिए, आपको सामान्य कार्यों या टेम्पलेट्स/जेनेरिक इनपुट की निश्चित संख्या से "एकाधिक रिटर्न" रखने के लिए std :: tuple का उपयोग नहीं करना चाहिए। इसके लिए एक असली संरचना का प्रयोग करें। एक वास्तविक वस्तु एफएआर है जो std :: tuple कुकी-कटर की तुलना में अधिक "जेनेरिक" है, क्योंकि आप वास्तविक वस्तु को सचमुच किसी भी इंटरफेस दे सकते हैं। यह आपको सार्वजनिक पुस्तकालयों में अधिक प्रकार की सुरक्षा और लचीलापन भी देगा।

बस इन 2 वर्ग के सदस्य कार्यों की तुलना:

std::tuple<double, double, double> GetLocation() const; // x, y, z 

GeoCoordinate GetLocation() const; 
एक असली के साथ

वस्तु मैं एक ऑपरेटर bool() कि झूठे लौटाता है यदि पैरेंट ऑब्जेक्ट कोई स्थान था प्रदान कर सकते हैं 'समन्वय भू'। अपने एपीआई के माध्यम से उपयोगकर्ता एक्स, वाई, जेड स्थानों को प्राप्त कर सकते हैं। लेकिन यहां बड़ी बात है- अगर मैं 6 महीने में समय क्षेत्र जोड़कर भू-समन्वय 4 डी बनाने का फैसला करता हूं, तो वर्तमान उपयोगकर्ता का कोड नहीं टूट जाएगा। मैं std :: tuple संस्करण के साथ ऐसा नहीं कर सकता।

1

मैं तिमिर के जवाब पर टिप्पणी नहीं कर सकता, तो मैं एक अलग जवाब देने के लिए होगा:

मुझे लगता है कि tuples मानक में शामिल किया गया यह भी कार्यात्मक शैली प्रोग्रामिंग के लिए अनुमति देने के लिए।उदाहरण के लिए, जबकि कोड

तरह
void my_func(const MyClass& input, MyClass& output1, MyClass& output2, MyClass& output3) 
{ 
    // whatever 
} 

, पारंपरिक सी ++ में सर्वव्यापी है, क्योंकि यह एक समारोह से वापस लौटे एक से अधिक ऑब्जेक्ट के लिए एक ही रास्ता है, इस कार्यात्मक प्रोग्रामिंग के लिए एक abomination है। अब आप

tuple<MyClass, MyClass, MyClass> my_func(const MyClass& input) 
{ 
    // whatever 
    return tuple<MyClass, MyClass, MyClass>(output1, output2, output3); 
} 

लिख सकते हैं इस प्रकार, दुष्प्रभाव और अस्थिरता से बचने के लिए पाइपलाइनिंग के लिए अनुमति देने के लिए, और, एक ही समय में, अपने कार्य का अर्थ शक्ति बनाए रखने के लिए मौका है।

+1

मानक आपत्ति: MyFuncReturn {MyClass output1, output2 को संरचित नहीं करेगा; }; MyFuncReturn my_func (MyClass const & input); बेहतर हो? अगर हम "अर्थात् ताकत" की बात कर रहे हैं, तो किसी उद्देश्य से निर्मित 'स्ट्रक्चर' में किसी भी 'tuple' की तुलना में कहीं अधिक है। निश्चित रूप से, यह फ़ंक्शन तर्कों के मौजूदा अर्थ के समानांतर होता है - जहां केवल ऑर्डर मायने रखता है, नाम नहीं - जो आपके लिए पर्याप्त हो सकता है। हालांकि, एक ही तर्क - अर्थपूर्ण अर्थ - यही कारण है कि लोग लगातार इस तरह की भाषाओं में नामित तर्क बनाने के लिए एक रास्ता खोजने की कोशिश कर रहे हैं, कुल टूटने/बेकारता के बिना। वे 'tuple' पर हँसेंगे। –

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