std :: pair <ऑटो, ऑटो> वापसी प्रकार


16

मैं के साथ चारों ओर खेल रहा था autoमें std::pair। नीचे दिए गए कोड में, फ़ंक्शन fको std::pairउन प्रकारों को वापस करना है जो टेम्पलेट पैरामीटर पर निर्भर करते हैं।

एक कार्य उदाहरण:

उदाहरण 1

template <unsigned S>
auto f()
{
    if constexpr (S == 1)
        return std::pair{1, 2}; // pair of ints
    else if constexpr (S == 2)
        return std::pair{1.0, 2.0}; // pair of doubles
    else
        return std::pair{0.0f, 0.0f}; // pair of floats
}

यह gcc 9.2, gcc 10.0, clang 9.0 और clang 10.0 के साथ काम करता है।

अगला, मैं std::pairस्पष्टता कारणों से स्पष्ट रूप से रिटर्न प्रकार लिखना चाहता था :

उदाहरण २

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return {1, 2};
    /* ... */
}

दोनों gcc 9.2 / 10.0 और clang 9.0 / 10.0 इसे संकलित करने में विफल रहे।

gcc 9.2

error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return

अंतिम त्रुटि संदेश से, gcc 9.2 यह मानता है कि std::pair<auto, auto>यह एक है int। इसे कैसे समझाया जा सकता है?

gcc 10.0

error: returning initializer list

यह त्रुटि समझ में आती है, हालाँकि, मुझे उम्मीद है कि कंस्ट्रक्टर std::pairको आमंत्रित किया जाएगा, या क्या ऐसा कुछ है जो मैं यहाँ याद कर रहा हूँ?

क्लैंग 9.0 और 10.0

'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'

ठीक है, क्लैंग को इनमें से कोई पसंद नहीं है। दूसरी त्रुटि संदेश से, ऐसा लगता है कि क्लैंग का यह भी मानना ​​है कि रिटर्न प्रकार है int

अंत में, जीसी 10.0 के साथ संकलित की गई त्रुटि को ठीक करने के लिए, मैंने std::pairस्पष्ट रूप से लौटने का फैसला किया :

उदाहरण ३

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return std::pair{1, 2};
    /* ... */
}

क्लैंग 9.0 और 10.0

पहले जैसा ही, लेकिन एक अतिरिक्त के साथ:

no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'

यहाँ क्लैंग को अभी भी लगता है कि हम वापस लौट रहे हैं int?

gcc 9.2

पहले की तरह।

gcc 10.0

यह काम करता हैं!

मुझे लगता है कि कुछ सुविधाओं को अभी भी लागू किया जाना है, या ऊपर वर्णित स्थितियों में से एक में, क्या एक संकलक है जो सही है और दूसरा गलत है? मेरी राय में, उदाहरण 2 को काम करना चाहिए। या नहीं करना चाहिए?

जवाबों:


23

वाक्य रचना:

std::pair<auto, auto> f() { return std::pair(1, 2); }
~~~~~~~~~~~~~~~~~~~~~

मूल अवधारणाओं टीएस का हिस्सा था, लेकिन कॉन्सेप्ट प्रस्ताव में शामिल नहीं था जो सी ++ 20 का हिस्सा है। जैसे, C ++ 20 में एकमात्र प्लेसहोल्डर प्रकार auto(और उसके प्रकार भिन्नरूप हैं auto**) decltype(auto), और विवश प्लेसहोल्डर ( Concept autoऔर उसके रूपांतर)। इस तरह के नेस्टेड प्लेसहोल्डर प्रकार बहुत उपयोगी होंगे, लेकिन सी ++ 20 का हिस्सा नहीं है, ताकि फ़ंक्शन की घोषणा बीमार हो।

अब, जीसीसी इसे अनुमति देता है क्योंकि जीसीसी ने अवधारणाओं को लागू किया है और मुझे लगता है कि उन्होंने इस सुविधा को बनाए रखने का फैसला किया है। clang ने TS को कभी लागू नहीं किया, इसलिए यह नहीं है।

किसी भी तरह से, यह:

std::pair<auto, auto> f() { return {1, 2}; }

हमेशा बीमार बनेगा। वाक्यविन्यास का अर्थ यह है कि हम रिटर्न प्रकार घटाते हैं और फिर आवश्यकता होती है कि यह pair<T, U>कुछ प्रकारों के लिए मेल खाता है Tऔर U। हम मूल रूप से आविष्कार किए गए कार्य को लागू करने की कोशिश कर रहे हैं:

template <typename T, typename U>
void __f(std::pair<T, U>);

__f({1, 2}); // this must succeed

लेकिन आप एक प्रकार से कटौती नहीं कर सकते {1, 2}- एक ब्रेडेड-इनिट-सूची में एक प्रकार नहीं है। शायद यह एक ऐसी चीज है जिसे खोजा जाना चाहिए (जैसा कि कम से कम इस तरह के एक साधारण मामले में समझना आसान है), लेकिन इसकी अनुमति कभी नहीं दी गई। इसलिए इसे अस्वीकार करना दोनों तरह से सही है।

अंततः:

9.2 gcc का मानना ​​है कि std::pair<auto, auto>यह एक है int। इसे कैसे समझाया जा सकता है?

किसी कारण से (संभवतः निहितार्थ के साथ हमारी सी विरासत के कारण int), जब जीसीसी एक प्रकार को नहीं पहचानता या समझता नहीं है, यह सिर्फ intत्रुटि संदेशों में प्लेसहोल्डर के रूप में उपयोग करता है । यह सुपर भ्रामक है, क्योंकि जाहिर है कि यह gcc है जो intस्रोत कोड के साथ आया है । लेकिन यह तरीका है।


"लट-इन-इन-लिस्ट में एक प्रकार का तर्क नहीं है" मेरे लिए स्पष्ट नहीं है। std :: pair <int, int> f () {वापसी {1,2}; } काम करता है, और {1,2} का कोई प्रकार नहीं है (यह std के निर्माता को आमंत्रित करता है :: जोड़ी <int, int> जैसा कि मैं इसे समझता हूं)। हो सकता है कि <ऑटो, ऑटो> के साथ, कंपाइलर प्रारंभिक सूची {1, 2} में 1, और 2 के प्रकारों को कम नहीं कर सकता है?
mfnx

@mfnx में एक प्रकार का तर्क नहीं है, बस एक प्रकार नहीं है। ब्रेडेड इनिट सूचियों का उपयोग केवल कुछ स्थितियों में किया जा सकता है - जैसे कि किसी ज्ञात प्रकार को प्रारंभ करना। लेकिन कटौती में उनका उपयोग नहीं किया जा सकता है - क्योंकि उनके पास कोई प्रकार नहीं है। auto x = {1, 2};कामों को छोड़कर , लेकिन केवल अगर सभी प्रकार समान हैं।
बैरी

2
अधिकांश कंपाइलर, पहली त्रुटि पर बस रोकने के बजाय, इससे उबरने का प्रयास करते हैं ताकि वे अतिरिक्त त्रुटियों की रिपोर्ट कर सकें। आमतौर पर इसका मतलब यह है कि सब कुछ अप्राप्य है int। ऐसा नहीं है कि intत्रुटि संदेशों में एक प्लेसहोल्डर है; संकलक वास्तव में सोचता है कि यह एक है int। (इसे स्पष्ट करने के लिए, gcc को किसी बिंदु पर "मान लेना int" कहना चाहिए था।)
रेमंड चेन

2
ध्यान दें कि एक्सटेंशन के लिए एक और संभावित एवेन्यू std::pair __f{1,2};काम करने के बाद से रिटर्न के प्रकारों के लिए क्लास टेम्पलेट तर्क कटौती की अनुमति देगा ।
डेविस हेरिंग 15

2
@DavisHerring मैं वास्तव में std::optional f() { return 4; }काम नहीं करना चाहूंगा ।
बैरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.