수색…


소개

함수에서 여러 값을 반환하는 것이 유용한 경우가 많이 있습니다. 예를 들어 항목을 입력하고 가격과 수량을 반환하려는 경우이 기능이 유용 할 수 있습니다. C ++에서 이것을 수행하는 많은 방법이 있으며, 대부분 STL이 관련되어 있습니다. 그러나 어떤 이유에서든 STL을 피하려면 structs/classesarrays 포함하여 여러 가지 방법이 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 사용하기

C ++ 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에서는, braced initializer list를 사용할 수 있습니다 :

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

반환 된 tuple 에서 값을 검색하는 것은 번거로울 수 있으므로 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);

함수가 반환되기 전에 형식을 선언 할 수 있으면 기존 변수에 tuple 을 언팩하는 데 std::tie 사용할 수 있습니다.

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);
C ++ 17

구조화 된 바인딩 을 사용하여 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::tie 대신에 std::tie std::forward_as_tuple 사용합니다. 일시적으로 오래 오래 걸리지 않을 수도 있으므로 그렇게 할 경우 조심하십시오.

std :: array 사용하기

C ++ 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 가 계산없이 배열의 크기를 리턴 할 수있다.

std :: pair 사용하기

구조체 템플릿 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 대신에 초기화리스트를 사용할 수 있습니다 :

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

쌍의 firstsecond 구성원 개체를 사용하여 반환 된 std::pair 의 개별 값을 검색 할 수 있습니다.

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

산출:

10

구조체 사용

struct 는 여러 개의 반환 값을 묶는 데 사용할 수 있습니다.

C ++ 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);
C ++ 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 사용할 때 반환 된 값은 단일 객체로 그룹화되어 의미있는 이름을 사용하여 액세스 할 수 있습니다. 이는 반환 값의 범위에서 생성 된 외부 변수의 수를 줄이는데도 도움이됩니다.

C ++ 17

함수에서 반환 된 struct 압축을 풀려면 구조화 된 바인딩을 사용할 수 있습니다. 이렇게하면 out 매개 변수가 in-parameters를 사용하여 균등하게 배치됩니다.

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

이 코드의 출력은 위와 동일합니다. struct 는 여전히 함수에서 값을 반환하는 데 사용됩니다. 이렇게하면 필드를 개별적으로 처리 할 수 ​​있습니다.

구조화 된 바인딩

C ++ 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_elementget 작성 :

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';
}

함수 개체 소비자 사용

우리는 여러 관련 가치로 불릴 소비자를 제공 할 수 있습니다 :

C ++ 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';
});

이것은 "연속 통과 스타일"이라고 합니다.

다음을 통해 튜플을 반환하는 함수를 연속 전달 스타일 함수에 적용 할 수 있습니다.

C ++ 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 사용하기

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