टेम्प्लेट में सही प्रकार का डेटा कैसे लौटाएं?


9
#include <iostream>
using namespace std;

template <class X, class Y>
Y big(X a, Y b)
{
   if (a > b)
      return (a);
   else return (b);
}

int main()
{
   cout << big(32.8, 9);
}

यहां मैं सीपीपी में टेम्प्लेट का उपयोग कर रहा हूं, इसलिए जब मैं फ़ंक्शन bigको टाइप doubleऔर intप्रकार के तर्कों को दरकिनार करता हूं, तो मुझे रिटर्न उत्तर चाहिए double। यहां टाइप 32करने के बजाय यह वापस आ जाता है 32.8

मुझे अपना वांछित आउटपुट कैसे मिलेगा? bigफ़ंक्शन का उचित वापसी प्रकार कैसे लिखें ?


1
एक फ़ंक्शन केवल एक निश्चित प्रकार वापस कर सकता है । आप रन-टाइम पर यह नहीं चुन सकते कि किस प्रकार का रिटर्न है।
जेसपर जुहल

1
आप देखना चाहते हैं कि कैसे std::maxलागू किया जाता है। फ़ंक्शन का वापसी प्रकार C ++ में संकलन समय पर जाना जाना चाहिए। इसलिए आपके पास यह रिटर्न प्रकार आपके मापदंडों के रनटाइम मूल्य पर निर्भर नहीं हो सकता है। यही कारण है कि इस तरह के फ़ंक्शन के लिए, आपको एक ही प्रकार (यानी, टाइप एक्स, लेकिन वाई नहीं) के लिए दोनों मापदंडों की आवश्यकता है।
बोरिस डालस्टेन

जवाबों:


12

एक फ़ंक्शन में केवल एक वापसी प्रकार हो सकता है जिसे संकलन समय पर जाना जाता है। हालाँकि, आप उपयोग कर सकते हैं std::common_type, एक ऐसे प्रकार को वापस करने के लिए जिसमें दोनों मापदंडों को परिवर्तित किया जा सकता है।

यह होगा

#include <type_traits>
template <class X, class Y>
typename std::common_type<X,Y>::type big(X a, Y b)
{
   if (a > b)
      return a;
   else return b;
}

और यह जांचने के लिए कि यह वास्तव में एक doubleपारित कर दिया गया है intऔर doubleहम क्या कर सकते हैं:

int main() {
    auto x = big(4.2,42);
    std::cout << std::is_same<decltype(x),double>::value;
}

जो प्रिंट करता है

1

पुनश्च: std::common_typescern के पीछे ternary ऑपरेटर का उपयोग कर सकते हैं और इस तरह के समाधान अन्य उत्तर ( auto+ ternary) से बहुत अलग नहीं है । असली शक्ति std::common_typeयह है कि यह किसी भी संख्या में मापदंडों को स्वीकार करता है।


10

वापसी प्रकार को संकलन-समय पर निर्धारित किया जाना चाहिए। आप एक सशर्त ऑपरेटर के साथ ट्रेलिंग रिटर्न का उपयोग कर सकते हैं , यदि आप सीमित हैं

template <typename X, typename Y>
auto big(X&& a, Y&& b) -> decltype(a > b ? a : b) // ---> like this
{
   return  a > b ? a : b;
}

लाइव देखें


हालांकि, अगर आपके पास पहुंच है या उच्चतर autoरिटर्न पर्याप्त है, क्योंकि कंपाइलर सही प्रकार घटाएगा यदि आप इसे सशर्त ऑपरेटर के साथ निम्नानुसार उपयोग करते हैं:

template <typename X, typename Y>
auto big(X a, Y b)
{
   return  a > b ? a : b;
}

लाइव देखें


ट्रेलिंग रिटर्न प्रकार की आवश्यकता नहीं है, कम से कम C ++ 14 के रूप में।
sweenish

@ ग्वाला अच्छी बात है। एक और विकल्प अग्रेषण संदर्भ है?
JeJo

1
@JeJo हां, मुझे लगता है कि यह ठीक है, लेकिन शायद व्यर्थ है, क्योंकि आप या तो तर्क को संशोधित नहीं कर रहे हैं और रिटर्न प्रकार अभी भी या तो मामले में एक अंतराल संदर्भ होगा (हालांकि संभावित रूप से गैर- const)।
अखरोट

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

यदि कोई आपके कोड को देखता है, तो ऐसा लगता है कि पारित पैरामीटर तय करेगा कि कौन सा रिटर्न टाइप किसी को मिलेगा जो कि नहीं है! आपको हमेशा एक डबल वापस मिलेगा, भले ही ए बी से बड़ा हो।
क्लॉस

4

के रूप में अपनी वापसी प्रकार अंकन में Yऔर एक गुजर intअपने दूसरे पैरामीटर के रूप में, आप स्पष्ट रूप से इंगित किया है कि Yहै एक int। यहाँ कोई आश्चर्य की बात नहीं है।

#include <iostream>

template <typename X, typename Y>
decltype(auto) big(const X& a, const Y& b)  // return type can just be auto as well 
{
    return a > b ? a : b;
}

int main()
{
    std::cout << big(32.8, 9) << '\n';
    std::cout << big(9, 32.8) << '\n';
    std::cout << big(32.8, 90) << '\n';
    std::cout << big(90, 32.8) << '\n';
}

यह स्क्रीन पर सभी चार सही मान प्रिंट करता है।

https://godbolt.org/z/fyGsmo

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

महत्वपूर्ण : अपरिभाषित व्यवहार से बचने के लिए मापदंडों को संदर्भ द्वारा लिया जाना चाहिए। यह वापसी प्रकार के साथ करना है जिसे मैं जिद्दी रूप से चिपका रहा हूं। decltype(auto)प्रकार के संदर्भ वापस कर सकते हैं। यदि आप फ़ंक्शन में कुछ स्थानीय लौटाते हैं (तर्क गिनती), तो आपको अपरिभाषित व्यवहार मिलता है।


@walnut संयोग से एक संदर्भ लौटाना इस साइट की तुलना में बहुत कठिन है जो इसे बाहर करता है। लेकिन अपरिभाषित व्यवहार के बारे में जानने के लिए अच्छा है। यह ऐसा नहीं है जैसा कि मैं वैसे भी कोड लिखूंगा; यह एक सवाल का जवाब है।
sweenish

1
आह। मैंने आपकी पहले की टिप्पणी को दो अलग-अलग बिंदुओं के रूप में पढ़ा और प्रभाव और कारण नहीं। मैं उचित संपादन कर सकता हूं।
sweenish

मैंने एक अतिरिक्त अस्वीकरण जोड़ा है।
sweenish

2

यह आपकी सटीक स्थिति के लिए सही समाधान नहीं है, सभी संभावना में - अन्य जवाब आपके द्वारा वांछित होने के बहुत करीब होने की संभावना है।

हालांकि, अगर आपको वास्तव में किसी कारण से रनटाइम पर पूरी तरह से विभिन्न प्रकारों को वापस करने की आवश्यकता है, तो सही समाधान (तब से) का उपयोग करना है std::variant, जो एक प्रकार का सुरक्षित संघ है।

#include <variant>

template <typename X, typename Y>
std::variant<X, Y> max(X a, Y b) {
  if (a > b)
    return std::variant<X, Y>(std::in_place_index_t<0>, a);
  else
    return std::variant<X, Y>(std::in_place_index_t<1>, b);
}

ध्यान दें कि तब ऑनर कॉलर पर लौटाए गए मूल्य से निपटने के लिए होता है, सबसे अधिक संभावना का उपयोग करना std::visitया पसंद करना।


-2

यह int लौटता है क्योंकि Y एक int है और यह 32.8 को इसमें डाल देता है। जब आप बड़े 32,82 कहते हैं, एक फ्लोट है, लेकिन 8 एक int है और फ़ंक्शन रिटर्न प्रकार Y है, जो कि int भी है।

आप वास्तव में इसे ठीक नहीं कर सकते हैं क्योंकि आपको रनटाइम के बारे में जानने की जरूरत है जो बड़े रिटर्न टाइप करते हैं, इसलिए इस तरह से ए और बी बनाएं:

    #include <iostream>
    using namespace std;

    template <typename X>

    X big (X a, X b)
    {
    if (a>b)
    return a;

    else return b;
    }

    int main()
    {
    cout<< big (32.8, 9.0);
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.