Std :: make_pair बनाम std :: pair का उद्देश्य क्या है?


180

का उद्देश्य क्या है std::make_pair?

सिर्फ क्यों नहीं std::pair<int, char>(0, 'a')?

क्या दोनों विधियों में कोई अंतर है?


6
C ++ 11 में, आप लगभग पूरी तरह से make_pair के बिना कर सकते हैं। मेरा जवाब देखिए ।
प्लेगहैमर

2
C ++ 17 में, std::make_pairबेमानी है। इस विवरण के नीचे एक उत्तर है।
ड्रू डॉर्मेन

जवाबों:


165

अंतर यह है कि std::pairआपको दोनों तत्वों के प्रकारों को निर्दिष्ट करने की आवश्यकता है, जबकि std::make_pairउन तत्वों के प्रकार के साथ एक जोड़ी बनाई जाएगी जो इसे पारित किए बिना, आपको यह बताने की आवश्यकता नहीं है। यही कारण है कि मैं विभिन्न डॉक्स वैसे भी इकट्ठा कर सकता हूं।

इस उदाहरण को http://www.cplusplus.com/reference/std/utility/make_pair/ से देखें

pair <int,int> one;
pair <int,int> two;

one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>

इसके निहितार्थ बोनस के अलावा, यदि आपने मेकप का उपयोग नहीं किया है तो आपको करना होगा

one = pair<int,int>(10,20)

हर बार जब आप एक को सौंपा, जो समय के साथ कष्टप्रद होगा ...


1
वास्तव में, प्रकारों को निर्दिष्ट करने की आवश्यकता के बिना संकलन समय पर घटाया जाना चाहिए।
चाद

@ इसके लिए, मुझे पता है कि उन दोनों का उपयोग कैसे किया जाए, अगर कोई कारण था तो मैं बस उत्सुक था std::make_pair। जाहिर है यह सिर्फ सुविधा के लिए है।

@ जय ऐसा दिखाई देगा।
तोर वालमो

15
मुझे लगता है कि आप one = {10, 20}आजकल कर सकते हैं लेकिन मेरे पास इसे जांचने के लिए C ++ 11 संकलक काम नहीं है।
एमएसएलटर्स

6
यह भी ध्यान दें कि make_pairसंरचना, यूनियनों, लंबदा और अन्य डूडोड सहित अनाम प्रकारों के साथ काम करता है।
मूविंग डक

35

जैसा कि @MSalters ने उत्तर दिया है, अब आप C ++ 11 में ऐसा करने के लिए घुंघराले ब्रेसिज़ का उपयोग कर सकते हैं (बस इसे C ++ 11 संकलक के साथ सत्यापित करें):

pair<int, int> p = {1, 2};

28

क्लास टेम्पलेट तर्क सी ++ 17 से पहले कंस्ट्रक्टर से अनुमान नहीं लगाया जा सकता है

C ++ 17 से पहले आप कुछ ऐसा नहीं लिख सकते थे:

std::pair p(1, 'a');

चूंकि वह कंस्ट्रक्टर के तर्कों से टेम्पलेट प्रकारों का अनुमान लगाएगा।

C ++ 17 उस वाक्यविन्यास को संभव बनाता है, और इसलिए make_pairनिरर्थक है।

C ++ 17 से पहले, std::make_pairहमें कम क्रिया कोड लिखने की अनुमति दी:

MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);

अधिक क्रिया के बजाय:

std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};

जो प्रकारों को दोहराता है, और बहुत लंबा हो सकता है।

उस पूर्व-सी ++ 17 केस में टाइप इंफ़ेक्शन काम करता है क्योंकि make_pairकंस्ट्रक्टर नहीं है।

make_pair अनिवार्य रूप से इसके बराबर है:

template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
    return std::pair<T1, T2>(t1, t2);
}

एक ही अवधारणा inserterबनाम पर लागू होती है insert_iterator

यह सभी देखें:

न्यूनतम उदाहरण

चीजों को अधिक ठोस बनाने के लिए, हम समस्या को न्यूनतम रूप से देख सकते हैं:

main.cpp

template <class MyType>
struct MyClass {
    MyType i;
    MyClass(MyType i) : i(i) {}
};

template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
    return MyClass<MyType>(i);
}

int main() {
    MyClass<int> my_class(1);
}

फिर:

g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp

खुशी से संकलित करता है, लेकिन:

g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp

के साथ विफल रहता है:

main.cpp: In function int main()’:
main.cpp:13:13: error: missing template arguments before my_class
     MyClass my_class(1);
             ^~~~~~~~

और काम करने के बजाय आवश्यकता होती है:

MyClass<int> my_class(1);

या सहायक:

auto my_class = make_my_class(1);

जो एक कंस्ट्रक्टर के बजाय एक नियमित फ़ंक्शन का उपयोग करता है।

`Std :: reference_wrapper के लिए अंतर

इस टिप्पणी को कहा गया है कि std::make_pairunwraps std::reference_wrapper, जबकि निर्माता नहीं करता है, तो यह है कि एक अंतर है। TODO उदाहरण।

जीसीसी 8.1.0, उबंटू 16.04 के साथ परीक्षण किया गया ।


1
"C ++ 17 उस वाक्यविन्यास को संभव बनाता है, और इसलिए make_pair बेमानी है।" - ऐसा क्यों है कि std::make_pairC ++ 17 में पदावनत नहीं किया गया?
andreee

@andreee मुझे यकीन नहीं है, संभावित कारण यह है कि यह कोई परेशानी पैदा करता है इसलिए पुराने कोड को तोड़ने की कोई आवश्यकता नहीं है? लेकिन मैं C ++ समिति के तर्क से परिचित नहीं हूं, अगर आप कुछ पाते हैं तो मुझे पिंग करें।
Ciro Santilli 郝海东 冠状 iro i 法轮功

1
एक उपयोगी बात जो मुझे पता चली है, वह यह है कि std :: make_pair <T1, T2> (o1, o2) के साथ प्रकारों को निर्दिष्ट करने में सक्षम होने के कारण उपयोगकर्ता को प्रकार o1 या o2 पास करने की गलती करने से रोकता है जो कि निहित नहीं हो सकता है T1 या T2 को कास्ट करें। उदाहरण के लिए, एक अनिर्दिष्ट int को ऋणात्मक संख्या पास करना। -साइन-कन्वर्जन -Werror std :: जोड़ी कंस्ट्रक्टर के साथ c ++ 11 में इस एरर को नहीं पकड़ेगा, हालांकि अगर std :: make_pair का उपयोग किया जाता है तो यह एरर पकड़ लेगा।
२०:३६ बजे

make_pair संदर्भ आवरणों को हटाता है, इसलिए यह वास्तव में CTAD से अलग है।
एलएफ

26

उपयोग करने के बीच कोई अंतर नहीं है make_pairpairनिर्दिष्ट प्रकार के तर्कों के साथ कंस्ट्रक्टर को और स्पष्ट रूप से कॉल करने के है। std::make_pairप्रकार सुविधाजनक होता है जब प्रकार क्रिया होते हैं क्योंकि एक टेम्पलेट विधि में दिए गए मापदंडों के आधार पर प्रकार में कटौती होती है। उदाहरण के लिए,

std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;

// shorter
vecOfPair.push_back(std::make_pair(emptyV, emptyV));

 // longer
vecOfPair.push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));

21

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

संपादित करें जैसा कि किसी ने टिप्पणियों में सुझाया है (हटाए जाने के बाद) यह टूटने की स्थिति में लिंक से थोड़ा संशोधित उद्धरण है।

ऑब्जेक्ट जेनरेटर उनके प्रकारों को स्पष्ट रूप से निर्दिष्ट किए बिना वस्तुओं के निर्माण की अनुमति देता है। यह फ़ंक्शन टेम्प्लेट्स की एक उपयोगी संपत्ति पर आधारित है, जो क्लास टेम्प्लेट नहीं है: किसी फ़ंक्शन टेम्प्लेट के प्रकार अपने वास्तविक मापदंडों से स्वचालित रूप से काटे जाते हैं। std::make_pairएक सरल उदाहरण है जो फ़ंक्शन std::pairके वास्तविक मापदंडों के आधार पर टेम्पलेट का एक उदाहरण देता std::make_pairहै।

template <class T, class U>
std::pair <T, U> 
make_pair(T t, U u)
{
  return std::pair <T, U> (t,u);
}

2
@duck वास्तव &&में C ++ 11 के बाद से।
Justme0

5

make_pair डायरेक्ट कंस्ट्रक्टर पर एक अतिरिक्त कॉपी बनाता है। मैं हमेशा अपने जोड़े को सरल वाक्य रचना प्रदान करने के लिए टाइप करता हूं।
यह अंतर दिखाता है (रामपाल चौधरी द्वारा उदाहरण):

class Sample
{
    static int _noOfObjects;

    int _objectNo;
public:
    Sample() :
        _objectNo( _noOfObjects++ )
    {
        std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
    }

    Sample( const Sample& sample) :
    _objectNo( _noOfObjects++ )
    {
        std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
    }

    ~Sample()
    {
        std::cout<<"Destroying object "<<_objectNo<<std::endl;
    }
};
int Sample::_noOfObjects = 0;


int main(int argc, char* argv[])
{
    Sample sample;
    std::map<int,Sample> map;

    map.insert( std::make_pair( 1, sample) );
    //map.insert( std::pair<int,Sample>( 1, sample) );
    return 0;
}

4
मुझे पूरा यकीन है कि अतिरिक्त कॉपी सभी मामलों में बढ़ाई जाएगी, अगर कंपाइलर की ऑप्टिमाइज़ेशन सेटिंग्स काफी अधिक हैं।
ब्योर्न पोलेक्स

1
आप कभी भी शुद्धता के लिए संकलक अनुकूलन पर भरोसा क्यों करना चाहेंगे?
sjbx

मुझे दोनों संस्करणों के साथ और std::moveसिर्फ अंदर insertऔर / या उसके आस-पास वही परिणाम मिलते हैं जो एक संदर्भ होगा sample। यह केवल तब होता है जब मैं बदलने std::map<int,Sample>के लिए std::map<int,Sample const&>है कि मैं का निर्माण वस्तुओं की संख्या को कम, और केवल जब मैं प्रतिलिपि निर्माता है कि मैं सभी प्रतियों (जाहिर है) को खत्म करने को हटा दें। उन दोनों परिवर्तनों को करने के बाद, मेरे परिणाम में डिफ़ॉल्ट निर्माता के लिए एक कॉल और एक ही ऑब्जेक्ट के लिए विध्वंसक को दो कॉल शामिल हैं। मुझे लगता है कि मुझे कुछ याद आ रहा होगा। (जी ++ 5.4.1, सी ++ 11)
जॉन पी

एफडब्ल्यूआईडब्ल्यू मैं सहमत हूं कि अनुकूलन और शुद्धता पूरी तरह से स्वतंत्र होनी चाहिए, क्योंकि यह बिल्कुल उसी तरह का कोड है जिसे आप अलग-अलग अनुकूलन स्तरों के बाद एक पवित्रता जांच के रूप में लिखते हैं। सामान्य तौर पर मैं इसके emplaceबजाय सिफारिश करूंगा कि insertयदि आप तुरंत सम्मिलित करने के लिए एक मान का निर्माण कर रहे हैं (और आप अतिरिक्त उदाहरण नहीं चाहते हैं।) यह मेरी विशेषज्ञता का क्षेत्र नहीं है, अगर मैं कह सकता हूं कि मेरे पास एक है, लेकिन प्रतिलिपि / चाल C ++ 11 द्वारा शुरू किए गए शब्दार्थ ने मुझे बहुत मदद की है।
जॉन पी

मेरा मानना ​​है कि मैं वास्तव में एक ही मुद्दे का सामना कर रहा हूं और पूरी शाम के लिए बहस करने के बाद, मैं आखिरकार यहां आया।
lllllllllllll

1

c ++ 11 से शुरू होकर जोड़े के लिए सिर्फ यूनिफॉर्म इनिशियलाइज़ेशन का उपयोग करें इसलिए इसके बजाय:

std::make_pair(1, 2);

या

std::pair<int, int>(1, 2);

महज प्रयोग करें

{1, 2};

{1, 2}एक जोड़ी को इनिशियलाइज़ करने के लिए इस्तेमाल किया जा सकता है, लेकिन टाइप पेयर के लिए प्रतिबद्ध नहीं है। यानी ऑटो का उपयोग करते समय आपको आरएचएस पर एक प्रकार के लिए प्रतिबद्ध होना चाहिए auto p = std::pair{"Tokyo"s, 9.00};:।
मार्कस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.