खोज…


परिचय

ऐसी कई स्थितियां हैं, जहां किसी फ़ंक्शन से कई मान वापस करना उपयोगी है: उदाहरण के लिए, यदि आप किसी आइटम को इनपुट करना चाहते हैं और स्टॉक में मूल्य और संख्या वापस करना चाहते हैं, तो यह कार्यक्षमता उपयोगी हो सकती है। C ++ में ऐसा करने के कई तरीके हैं, और अधिकांश में STL शामिल है। हालाँकि, यदि आप किसी कारण से एसटीएल से बचना चाहते हैं, तो इसके लिए अभी भी कई तरीके हैं, जिनमें structs/classes और arrays

आउटपुट पैरामीटर का उपयोग करना

पैरामीटर का उपयोग एक या अधिक मूल्यों को वापस करने के लिए किया जा सकता है; उन मापदंडों को नॉन- const पॉइंटर्स या संदर्भों की आवश्यकता होती है।

संदर्भ:

void calculate(int a, int b, int& c, int& d, int& e, int& f) {
    c = a + b;
    d = a - b;
    e = a * b;
    f = a / b;
}

संकेत:

void calculate(int a, int b, int* c, int* d, int* e, int* f) {
    *c = a + b;
    *d = a - b;
    *e = a * b;
    *f = a / b;
}

कुछ पुस्तकालयों या चौखटे एक खाली 'OUT' #define का उपयोग करते हैं ताकि यह स्पष्ट रूप से स्पष्ट हो सके कि फ़ंक्शन हस्ताक्षर में कौन से पैरामीटर आउटपुट पैरामीटर हैं। इसका कोई कार्यात्मक प्रभाव नहीं है, और इसे संकलित किया जाएगा, लेकिन फ़ंक्शन हस्ताक्षर को थोड़ा स्पष्ट करता है;

#define OUT

void calculate(int a, int b, OUT int& c) {
    c = a + b;
}

Std :: tuple का उपयोग करना

सी ++ 11

प्रकार std::tuple किसी भी मान को संभावित रूप से अलग-अलग प्रकार के मानों सहित एकल रिटर्न ऑब्जेक्ट में बंडल कर सकता है:

std::tuple<int, int, int, int> foo(int a, int b) { // or auto (C++14)
   return std::make_tuple(a + b, a - b, a * b, a / b);
}

C ++ 17 में, एक लट आरंभिक सूची का उपयोग किया जा सकता है:

सी ++ 17
std::tuple<int, int, int, int> foo(int a, int b)    {
    return {a + b, a - b, a * b, a / b};
}

लौटाए गए tuple से मानों को पुनः प्राप्त करना बोझिल हो सकता है, जिसमें std::get के उपयोग की आवश्यकता होती है std::get टेम्पलेट फ़ंक्शन std::get :

auto mrvs = foo(5, 12);
auto add = std::get<0>(mrvs);
auto sub = std::get<1>(mrvs);
auto mul = std::get<2>(mrvs);
auto div = std::get<3>(mrvs);

यदि फ़ंक्शन वापस आने से पहले प्रकार घोषित किए जा सकते हैं, तो std::tie को मौजूदा वेरिएबल्स में tuple को अनपैक करने के लिए नियोजित किया जा सकता है:

int add, sub, mul, div;
std::tie(add, sub, mul, div) = foo(5, 12);

यदि दिए गए मानों में से एक की आवश्यकता नहीं है, तो std::ignore का उपयोग किया जा सकता है:

std::tie(add, sub, std::ignore, div) = foo(5, 12);
सी ++ 17

संरचित बाइंडिंग का उपयोग std::tie से बचने के लिए किया जा सकता है std::tie :

auto [add, sub, mul, div] = foo(5,12);

यदि आप मानों के टपल के बजाय लवल्यू संदर्भों का एक टपल लौटना चाहते हैं, तो std::make_tuple स्थान पर std::make_tuple std::tie उपयोग करें।

std::tuple<int&, int&> minmax( int& a, int& b ) {
  if (b<a)
    return std::tie(b,a);
  else
    return std::tie(a,b);
}

जो अनुमति देता है

void increase_least(int& a, int& b) {
  std::get<0>(minmax(a,b))++;
}

कुछ दुर्लभ मामलों में आप इस्तेमाल करेंगे std::forward_as_tuple के बजाय std::tie ; यदि आप ऐसा करते हैं तो सावधान रहें, क्योंकि अस्थायी तौर पर लंबे समय तक सेवन नहीं किया जा सकता है।

Std :: array का उपयोग करना

सी ++ 11

कंटेनर std::array रिटर्न मानों की एक निश्चित संख्या को एक साथ बंडल कर सकती है। यह संख्या संकलन-समय पर जानी जाती है और सभी रिटर्न मान एक ही प्रकार के होते हैं:

std::array<int, 4> bar(int a, int b) {
    return { a + b, a - b, a * b, a / b };
}

यह प्रपत्र int bar[4] c शैली सरणियों को प्रतिस्थापित करता है। लाभ यह है कि विभिन्न c++ std फ़ंक्शन का उपयोग अब इस पर किया जा सकता है। यह भी उपयोगी सदस्य कार्य प्रदान की तरह at जो बाध्य जाँच के साथ एक सुरक्षित सदस्य पहुँच समारोह है, और size जो आप गणना के बिना सरणी के आकार वापस जाने के लिए अनुमति देता है।

एसटीडी :: जोड़ी का उपयोग करना

Struct टेम्पलेट std::pair किसी भी दो प्रकार के एक साथ ठीक दो वापसी मान बंडल कर सकते हैं:

#include <utility>
std::pair<int, int> foo(int a, int b) {
    return std::make_pair(a+b, a-b);
}

C ++ 11 या बाद के संस्करण के साथ, एक प्रारंभिक सूची का उपयोग std::make_pair बजाय किया जा सकता है:

सी ++ 11
#include <utility>
std::pair<int, int> foo(int a, int b) {
    return {a+b, a-b};
}

लौटे std::pair व्यक्तिगत मूल्य std::pair को जोड़ी की first और second सदस्य वस्तुओं का उपयोग करके पुनर्प्राप्त किया जा सकता है:

std::pair<int, int> mrvs = foo(5, 12);
std::cout << mrvs.first + mrvs.second << std::endl;

आउटपुट:

10

संरचना का उपयोग करना

एक struct का उपयोग कई रिटर्न मानों को बंडल करने के लिए किया जा सकता है:

सी ++ 11
struct foo_return_type {
    int add;
    int sub;
    int mul;
    int div;
};

foo_return_type foo(int a, int b) {
    return {a + b, a - b, a * b, a / b};
}

auto calc = foo(5, 12);
सी ++ 11

अलग-अलग क्षेत्रों को असाइन करने के बजाय, एक निर्माता का उपयोग लौटे मूल्यों के निर्माण को सरल बनाने के लिए किया जा सकता है:

struct foo_return_type {
    int add;
    int sub;
    int mul;
    int div;
    foo_return_type(int add, int sub, int mul, int div)
    : add(add), sub(sub), mul(mul), div(div) {}
};

foo_return_type foo(int a, int b) {
     return foo_return_type(a + b, a - b, a * b, a / b);
}

foo_return_type calc = foo(5, 12);

फ़ंक्शन foo() द्वारा लौटाए गए व्यक्तिगत परिणामों को struct calc के सदस्य चर तक पहुंचकर प्राप्त किया जा सकता है:

std::cout << calc.add << ' ' << calc.sub << ' ' << calc.mul << ' ' << calc.div << '\n';

आउटपुट:

17 -7 60 0

नोट: किसी struct का उपयोग करते समय, लौटे हुए मानों को एक ही वस्तु में एक साथ रखा जाता है और सार्थक नामों का उपयोग करके सुलभ किया जाता है। यह लौटे हुए मानों के दायरे में बनाए गए बाहरी चर की संख्या को कम करने में भी मदद करता है।

सी ++ 17

किसी फ़ंक्शन से लौटे एक struct को अनपैक करने के लिए, संरचित बाइंडिंग का उपयोग किया जा सकता है। यह इन-पैरामीटर्स के साथ समान स्तर पर आउट-पैरामीटर रखता है:

int a=5, b=12;
auto[add, sub, mul, div] = foo(a, b);
std::cout << add << ' ' << sub << ' ' << mul << ' ' << div << '\n';

इस कोड का आउटपुट ऊपर के समान है। struct अभी भी फ़ंक्शन से मानों को वापस करने के लिए उपयोग की जाती है। यह आपको व्यक्तिगत रूप से खेतों से निपटने की अनुमति देता है।

संरचित बाइंडिंग

सी ++ 17

C ++ 17 संरचित बाइंडिंग का परिचय देता है, जो कई प्रकार के रिटर्न से निपटने में आसान बनाता है, क्योंकि आपको std::tie() पर भरोसा करने की कोई आवश्यकता नहीं है या कोई मैनुअल ट्यूपल अनपैकिंग करें:

std::map<std::string, int> m;

// insert an element into the map and check if insertion succeeded
auto [iterator, success] = m.insert({"Hello", 42});

if (success) {
    // your code goes here
}

// iterate over all elements without having to use the cryptic 'first' and 'second' names
for (auto const& [key, value] : m) {
    std::cout << "The value for " << key << " is " << value << '\n';
}

संरचित बाइंडिंग का उपयोग डिफ़ॉल्ट रूप से std::pair , std::tuple , और किसी भी प्रकार के गैर-स्थैतिक डेटा सदस्यों के साथ किया जा सकता है, जो या तो सार्वजनिक प्रत्यक्ष सदस्य हैं या असंदिग्ध आधार वर्ग के सदस्य हैं:

struct A { int x; };
struct B : A { int y; };
B foo();

// with structured bindings
const auto [x, y] = foo();

// equivalent code without structured bindings
const auto result = foo();
auto& x = result.x;
auto& y = result.y;

यदि आप अपना टाइप "टपल-लाइक" बनाते हैं, तो यह आपके प्रकार के साथ स्वचालित रूप से भी काम करेगा। एक टपल की तरह उचित साथ एक प्रकार है tuple_size , tuple_element और get लिखा:

namespace my_ns {
    struct my_type {
        int x;
        double d;
        std::string s;
    };
    struct my_type_view {
        my_type* ptr;
    };
}

namespace std {
    template<>
    struct tuple_size<my_ns::my_type_view> : std::integral_constant<std::size_t, 3>
    {};

    template<> struct tuple_element<my_ns::my_type_view, 0>{ using type = int; };
    template<> struct tuple_element<my_ns::my_type_view, 1>{ using type = double; };
    template<> struct tuple_element<my_ns::my_type_view, 2>{ using type = std::string; };
}

namespace my_ns {
    template<std::size_t I>
    decltype(auto) get(my_type_view const& v) {
        if constexpr (I == 0)
            return v.ptr->x;
        else if constexpr (I == 1)
            return v.ptr->d;
        else if constexpr (I == 2)
            return v.ptr->s;
        static_assert(I < 3, "Only 3 elements");
    }
}

अब यह काम करता है:

my_ns::my_type t{1, 3.14, "hello world"};

my_ns::my_type_view foo() {
    return {&t};
}

int main() {
    auto[x, d, s] = foo();
    std::cout << x << ',' << d << ',' << s << '\n';
}

एक फंक्शन ऑब्जेक्ट उपभोक्ता का उपयोग करना

हम एक उपभोक्ता प्रदान कर सकते हैं जिसे कई प्रासंगिक मूल्यों के साथ बुलाया जाएगा:

सी ++ 11
template <class F>
void foo(int a, int b, F consumer) {
    consumer(a + b, a - b, a * b, a / b);
}

// use is simple... ignoring some results is possible as well
foo(5, 12, [](int sum, int , int , int ){
    std::cout << "sum is " << sum << '\n';
});

इसे "निरंतर गुजर शैली" के रूप में जाना जाता है।

आप एक ट्यूल को लौटाने वाले फ़ंक्शन को एक सतत पासिंग स्टाइल फ़ंक्शन के माध्यम से अनुकूलित कर सकते हैं:

सी ++ 17
template<class Tuple>
struct continuation {
  Tuple t;
  template<class F>
  decltype(auto) operator->*(F&& f)&&{
    return std::apply( std::forward<F>(f), std::move(t) );
  }
};
std::tuple<int,int,int,int> foo(int a, int b);

continuation(foo(5,12))->*[](int sum, auto&&...) {
  std::cout << "sum is " << sum << '\n';
};

अधिक जटिल संस्करणों के साथ C ++ 14 या C ++ 11 में लिखने योग्य है।

एसटीडी :: वेक्टर का उपयोग करना

एक std::vector एक ही प्रकार के चर की एक गतिशील संख्या को वापस करने के लिए उपयोगी हो सकता है। निम्नलिखित उदाहरण डेटा प्रकार के रूप में int का उपयोग करता है, लेकिन एक std::vector किसी भी प्रकार को पकड़ सकता है जो तुच्छ रूप से प्रतिलिपि योग्य है:

#include <vector>
#include <iostream>

// the following function returns all integers between and including 'a' and 'b' in a vector
// (the function can return up to std::vector::max_size elements with the vector, given that
// the system's main memory can hold that many items)
std::vector<int> fillVectorFrom(int a, int b) {
    std::vector<int> temp;
    for (int i = a; i <= b; i++) {
        temp.push_back(i);
    }
    return temp;
}

int main() {    
    // assigns the filled vector created inside the function to the new vector 'v'
    std::vector<int> v = fillVectorFrom(1, 10);

    // prints "1 2 3 4 5 6 7 8 9 10 "
    for (int i = 0; i < v.size(); i++) {
        std::cout << v[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

आउटपुट इटरेटर का उपयोग करना

एक ही प्रकार के कई मान फ़ंक्शन में आउटपुट पुनरावृत्ति पास करके लौटाए जा सकते हैं। यह सामान्य कार्यों (मानक पुस्तकालय के एल्गोरिदम की तरह) के लिए विशेष रूप से आम है।

उदाहरण:

template<typename Incrementable, typename OutputIterator>
void generate_sequence(Incrementable from, Incrementable to, OutputIterator output) {
    for (Incrementable k = from; k != to; ++k)
        *output++ = k;
}

उदाहरण उपयोग:

std::vector<int> digits;
generate_sequence(0, 10, std::back_inserter(digits));
// digits now contains {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow