C ++ 함수에서 여러 값 반환


242

C ++ 함수에서 여러 값을 반환하는 선호되는 방법이 있습니까? 예를 들어, 두 정수를 나누고 몫과 나머지를 모두 반환하는 함수를 상상해보십시오. 내가 일반적으로 보는 한 가지 방법은 참조 매개 변수를 사용하는 것입니다.

void divide(int dividend, int divisor, int& quotient, int& remainder);

변형은 하나의 값을 반환하고 다른 하나는 참조 매개 변수를 통해 전달하는 것입니다.

int divide(int dividend, int divisor, int& remainder);

다른 방법은 모든 결과를 포함하도록 구조체를 선언하고 다음을 반환하는 것입니다.

struct divide_result {
    int quotient;
    int remainder;
};

divide_result divide(int dividend, int divisor);

이러한 방법 중 하나가 일반적으로 선호되거나 다른 제안이 있습니까?

편집 : 실제 코드에서 두 개 이상의 결과가있을 수 있습니다. 또한 유형이 다를 수 있습니다.

답변:


217

두 개의 값을 반환하기 위해 std::pair(보통 typedef'd)를 사용합니다. 두 개 이상의 반환 결과를 보려면 boost::tuple(C ++ 11 이상에서는 std::tuple)을 살펴보십시오 .

C ++ 17에 구조적 바인딩이 도입되면 반환 std::tuple이 표준으로 받아 들여질 것입니다.


12
튜플의 경우 +1 참조로 전달하는 것과 비교하여 구조로 반환되는 큰 객체의 성능 저하를 명심하십시오.
Marcin

12
튜플을 사용하려면 튜플도 사용하지 마십시오. 특별한 경우가있는 이유는 무엇입니까?
Ferruccio

4
Fred, yes boost :: tuple do
it

46
C ++ 11에서는을 사용할 수 있습니다 std::tuple.
Ferruccio

14
함수에서 여러 값을 받아들이려면 편리한 방법은 std::tie stackoverflow.com/a/2573822/502144
fdermishin

176

C ++ 11에서는 다음을 수행 할 수 있습니다.

#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
    return  std::make_tuple(dividend / divisor, dividend % divisor);
}

#include <iostream>

int main() {
    using namespace std;

    int quotient, remainder;

    tie(quotient, remainder) = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

C ++ 17에서 :

#include <tuple>

std::tuple<int, int> divide(int dividend, int divisor) {
    return  {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
    using namespace std;

    auto [quotient, remainder] = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

또는 구조체와 함께 :

auto divide(int dividend, int divisor) {
    struct result {int quotient; int remainder;};
    return result {dividend / divisor, dividend % divisor};
}

#include <iostream>

int main() {
    using namespace std;

    auto result = divide(14, 3);

    cout << result.quotient << ',' << result.remainder << endl;

    // or

    auto [quotient, remainder] = divide(14, 3);

    cout << quotient << ',' << remainder << endl;
}

4
튜플을 반환하는 함수에 대한 한 가지 우려가 있습니다. 위의 함수 프로토 타입이 헤더에 있다고 가정하면 함수 정의를 이해하지 않고 첫 번째와 두 번째 반환 값이 무엇을 의미하는지 어떻게 알 수 있습니까? 몫-나머지 또는 나머지 몫.
Uchia Itachi

7
@UchiaItachi 함수 매개 변수에 대한 동일한 관심사, 당신은 그들에게 이름을 줄 수 있지만 언어는 그것을 강제하지 않으며, 매개 변수 이름은 읽을 때 호출 사이트에서 가치가 없습니다. 또한 단일 반환시 유형 만 있지만 이름을 갖는 것도 유용 할 수 있습니다. 튜플을 사용하면 문제를 두 배로 늘릴 수 있으므로이 언어뿐만 아니라 여러 가지 방법으로 자체 문서화에 관한 언어가 부족합니다.
pepper_chico

1
나누기의 반환 유형을 명시 적으로 지정하려면 마지막 예제는 어떻게 보입니까? 그런 다음 결과를 다른 곳에 정의해야합니까, 아니면 반환 형식 사양에서 바로 정의 할 수 있습니까?
Slava

1
당신은 함수 서명에서 형의 권리를 정의 할 수 @Slava, 당신은 유형의 외부를 선언하고이 정상적으로 이루어처럼 바로 이동 (, 반환 형식으로 사용해야 struct함수 본문 외부 회선 및 교체 auto와 함수 반환을 result.
pepper_chico

3
@pepper_chico 함수 정의를 divide별도의 cpp 파일 에 넣으려면 어떻게해야 합니까? 오류가 발생 error: use of ‘auto divide(int, int)’ before deduction of ‘auto’합니다. 이 문제를 어떻게 해결합니까?
Adriaan

123

개인적으로 나는 일반적으로 여러 가지 이유로 반환 매개 변수를 싫어합니다.

  • 어떤 매개 변수가 있고 어떤 것이 호출인지 항상 명확하지는 않습니다.
  • 일반적으로 결과를 잡기 위해 지역 변수를 만들어야하지만 반환 값은 인라인으로 사용할 수 있습니다 (좋은 아이디어 일 수도 있고 아닐 수도 있지만 적어도 옵션이 있습니다)
  • 함수에 "in door"와 "out door"가있는 것이 더 깨끗해 보입니다. 모든 입력이 여기로 들어가고 모든 출력이 여기로 나옵니다.
  • 논증 목록을 가능한 한 짧게 유지하고 싶습니다

또한 쌍 / 튜플 기술에 대한 예약이 있습니다. 주로 반환 값에 대한 자연스러운 순서가없는 경우가 많습니다. 코드 리더는 result.first가 몫인지 나머지인지 어떻게 알 수 있습니까? 그리고 구현자는 순서를 변경하여 기존 코드를 손상시킬 수 있습니다. 컴파일러 오류 또는 경고가 생성되지 않도록 값이 동일한 유형 인 경우 특히 교묘합니다. 실제로 이러한 인수는 매개 변수를 반환하는 데에도 적용됩니다.

다음은 또 다른 코드 예제입니다.

pair<double,double> calculateResultingVelocity(double windSpeed, double windAzimuth,
                                               double planeAirspeed, double planeCourse);

pair<double,double> result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.first << endl;
cout << result.second << endl;

이것은 지상 속도와 코스 또는 코스와 지상 속도를 인쇄합니까? 분명하지 않습니다.

이것과 비교하십시오 :

struct Velocity {
    double speed;
    double azimuth;
};
Velocity calculateResultingVelocity(double windSpeed, double windAzimuth,
                                    double planeAirspeed, double planeCourse);

Velocity result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.speed << endl;
cout << result.azimuth << endl;

나는 이것이 더 분명하다고 생각합니다.

그래서 나는 일반적으로 첫 번째 선택은 구조체 기술이라고 생각합니다. 쌍 / 튜플 아이디어는 특정 경우에 훌륭한 솔루션 일 것입니다. 가능한 경우 반환 매개 변수를 피하고 싶습니다.


1
struct같은 것을 선언하는 제안 Velocity은 좋은 것입니다. 그러나 한 가지 우려는 네임 스페이스를 오염 시킨다는 것입니다. C ++ 11 struct을 사용하면 긴 유형 이름을 가질 수 있고 사용할 수 있다고 가정합니다 auto result = calculateResultingVelocity(...).
Hugues

5
+1. 함수는 어떻게 든 순서가 지정된 "tuple of things"가 아닌 하나의 "thing"을 반환해야합니다 .
DevSolar

1
이 답변에 설명 된 이유로 std :: pairs / std :: tuples보다 구조체를 선호합니다. 하지만 네임 스페이스 "pollution"도 마음에 들지 않습니다. 나를위한 이상적인 솔루션은와 같은 익명의 구조체를 반환하는 것 struct { int a, b; } my_func();입니다. 이것은 다음과 같이 사용될 수 있습니다 auto result = my_func();. 그러나 C ++에서는이를 허용하지 않습니다. "새 유형은 리턴 유형으로 정의되지 않을 수 있습니다". 따라서 다음과 같은 구조체를 만들어야합니다 struct my_func_result_t.
anton_rh

2
@anton_rh : C ++ 14는로 로컬 타입을 반환 할 수 auto있기 때문에 간단하게 auto result = my_func();얻을 수 있습니다.
ildjarn

4
약 15 년 전에 부스트를 발견했을 때 튜플을 많이 사용했기 때문에 매우 편리했습니다. 시간이 지남에 따라 동일한 유형을 가진 튜플 (예 : tuple <double, double>; 어느 것이 어느 것)에 대한 가독성의 단점을 경험했습니다. 요즘 우리는 최소한 멤버 변수의 이름이 뭔가 의미있는 것을 나타내는 작은 POD 구조를 도입하는 습관을 들이고 있습니다.
gast128

24
std::pair<int, int> divide(int dividend, int divisor)
{
   // :
   return std::make_pair(quotient, remainder);
}

std::pair<int, int> answer = divide(5,2);
 // answer.first == quotient
 // answer.second == remainder

std :: pair는 본질적으로 struct 솔루션이지만 이미 정의되어 있으며 두 가지 데이터 유형에 맞게 조정할 수 있습니다.


3
그것은 간단한 예제에서 작동합니다. 그러나 일반적으로 두 개 이상의 값이 반환 될 수 있습니다.
프레드 라슨

5
자체 문서화도 아닙니다. DIV의 나머지 x86 레지스터를 기억하십니까?
Mark

1
@Mark-위치 솔루션의 유지 관리가 쉽지 않을 수 있음에 동의합니다. "permute and baffle"문제가 발생할 수 있습니다.
프레드 라슨

16

실제 기능과 여러 값의 의미 및 크기에 전적으로 의존합니다.

  • 그것들이 분수 예제와 관련이 있다면 구조체 또는 클래스 인스턴스와 함께 갈 것입니다.
  • 그것들이 실제로 관련이 없으며 클래스 / 구조체로 그룹화 할 수 없다면 메소드를 두 가지로 리팩토링해야합니다.
  • 반환하는 값의 메모리 내 크기에 따라 클래스 인스턴스 또는 구조체에 대한 포인터를 반환하거나 참조 매개 변수를 사용할 수 있습니다.

1
나는 당신의 대답을 좋아하고 마지막 글 머리 기호는 상황을 더 복잡하게 만드는 상황에 따라 가치를 전달하는 것이 훨씬 빨라 졌다는 것을 상기시켜줍니다 ... cpp-next.com/archive/2009/08/want-speed-pass 값별
sage

12

이를위한 OO 솔루션은 비율 클래스를 작성하는 것입니다. 추가 코드 (일부 저장)가 필요하지 않으며 훨씬 깨끗하고 명확 하며이 클래스 외부에서 코드를 정리할 수있는 추가 리팩토링을 제공합니다.

실제로 누군가가 구조를 반환하는 것이 좋습니다.이 구조는 충분히 가깝지만 생성자와 몇 가지 메소드, 실제로는 원래 언급 한 "메소드"를 가진 완전히 생각하는 클래스가되어야한다는 의도를 숨 깁니다. pair) 자신의 인스턴스를 반환하는이 클래스의 멤버 일 가능성이 높습니다.

나는 당신의 예제가 단지 "예"라는 것을 알고 있지만 사실 함수가 수행 해야하는 것보다 더 많은 기능을 수행하지 않는 한 여러 값을 반환하려면 객체가 거의 누락 된 것입니다.

OO의 마법 인 작은 작업을 수행하기 위해이 작은 클래스를 만드는 것을 두려워하지 마십시오. 모든 방법이 매우 작고 단순하며 모든 클래스가 작고 이해할 수있을 때까지 분해합니다.

OO에는 본질적으로 데이터가 없습니다. OO는 데이터를 전달하는 것이 아니며 클래스는 내부적으로 자체 데이터를 관리하고 조작해야합니다 (액세서 ​​포함) 무언가를 다시 생각해야 할 수도 있다는 표시입니다.


10

의 C 구조체를 리턴 (따라서 C ++)이 표준에 대한 선례가 div, ldiv(C99, 그리고 lldiv부터) 함수 <stdlib.h>(또는 <cstdlib>).

'반환 값과 반환 매개 변수의 혼합'은 일반적으로 가장 깨끗하지 않습니다.

함수가 리턴 매개 변수를 통해 상태를 리턴하고 데이터를 리턴하게하는 것은 C에서 의미가 있습니다. C ++에서는 예외를 사용하여 실패 정보를 대신 릴레이 할 수있는 분명하지 않습니다.

반환 값이 두 개 이상인 경우 구조와 유사한 메커니즘이 가장 좋습니다.


10

C ++ 17을 사용하면 하나 이상의 이동 불가능 / 복사 불가능한 값을 반환 할 수도 있습니다 (특정 경우). 움직일 수없는 유형을 반환 할 수있는 가능성은 새로운 보장 된 반환 값 최적화를 통해 제공되며 집계템플릿 생성자 라고하는 항목으로 구성 됩니다.

template<typename T1,typename T2,typename T3>
struct many {
  T1 a;
  T2 b;
  T3 c;
};

// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;

auto f(){ return many{string(),5.7, unmovable()}; }; 

int main(){
   // in place construct x,y,z with a string, 5.7 and unmovable.
   auto [x,y,z] = f();
}

이것에 대한 예쁜 점은 복사 또는 이동을 유발 하지 않는다는 것 입니다. 예제 manystruct를 variadic으로 만들 수도 있습니다. 자세한 내용은:

C ++ 17 variadic template 'construction deduction guide'에 대한 variadic 집계 (struct)와 구문 반환


6

여러 매개 변수를 반환하는 방법에는 여러 가지가 있습니다. 나는 광대 할 것이다.

참조 매개 변수를 사용하십시오.

void foo( int& result, int& other_result );

포인터 매개 변수를 사용하십시오.

void foo( int* result, int* other_result );

당신이해야 할 장점이 &호출 사이트에서 호출 .

템플릿을 작성하여 사용하십시오.

template<class T>
struct out {
  std::function<void(T)> target;
  out(T* t):target([t](T&& in){ if (t) *t = std::move(in); }) {}
  out(std::optional<T>* t):target([t](T&& in){ if (t) t->emplace(std::move(in)); }) {}
  out(std::aligned_storage_t<sizeof(T), alignof(T)>* t):
    target([t](T&& in){ ::new( (void*)t ) T(std::move(in)); } ) {}
  template<class...Args> // TODO: SFINAE enable_if test
  void emplace(Args&&...args) {
    target( T(std::forward<Args>(args)...) );
  }
  template<class X> // TODO: SFINAE enable_if test
  void operator=(X&&x){ emplace(std::forward<X>(x)); }
  template<class...Args> // TODO: SFINAE enable_if test
  void operator()(Args...&&args){ emplace(std::forward<Args>(args)...); }
};

우리는 할 수 있습니다 :

void foo( out<int> result, out<int> other_result )

그리고 모두 좋다. foo더 이상 보너스로 전달 된 값을 읽을 수 없습니다.

데이터를 넣을 수있는 지점을 정의하는 다른 방법을 사용하여 구성 할 수 있습니다 out . 예를 들어 어딘가에 물건을 배치하는 콜백.

구조체를 반환 할 수 있습니다 :

struct foo_r { int result; int other_result; };
foo_r foo();

whick은 모든 버전의 C ++에서 정상적으로 작동합니다. 이것은 또한 다음을 허용합니다.

auto&&[result, other_result]=foo();

제로 비용으로. 제거가 보장되어 매개 변수를 옮길 수도 없습니다.

우리는 다음을 반환 할 수 있습니다 std::tuple:

std::tuple<int, int> foo();

매개 변수의 이름이 지정되지 않은 단점이 있습니다. 이것은:

auto&&[result, other_result]=foo();

게다가. 앞서서 우리는 대신 할 수 있습니다 :

int result, other_result;
std::tie(result, other_result) = foo();

조금 더 어색합니다. 그러나 보장 된 제거는 여기서 작동하지 않습니다.

낯선 영역으로 들어가면 (다음에 out<>!) 연속 전달 스타일을 사용할 수 있습니다.

void foo( std::function<void(int result, int other_result)> );

이제 발신자는 다음을 수행합니다.

foo( [&](int result, int other_result) {
  /* code */
} );

이 스타일의 이점은 메모리를 관리하지 않고도 임의의 수의 값 (균일 한 유형)을 반환 할 수 있다는 것입니다.

void get_all_values( std::function<void(int)> value )

value콜백 할 때 500 번을 호출 할 수 있습니다 get_all_values( [&](int value){} ).

순수한 광기를 위해 연속에서 연속을 사용할 수도 있습니다.

void foo( std::function<void(int, std::function<void(int)>)> result );

그 사용법은 다음과 같습니다.

foo( [&](int result, auto&& other){ other([&](int other){
  /* code */
}) });

그 사이 많은 한 관계를 허용하는 것 result등을 other.

uniforn 값을 사용하면 다음과 같이 할 수 있습니다.

void foo( std::function< void(span<int>) > results )

여기서는 다양한 결과로 콜백을 호출합니다. 우리는 이것을 반복해서 할 수도 있습니다.

이를 사용하면 스택에서 할당하지 않고 메가 바이트의 데이터를 효율적으로 전달하는 기능을 가질 수 있습니다.

void foo( std::function< void(span<int>) > results ) {
  int local_buffer[1024];
  std::size_t used = 0;
  auto send_data=[&]{
    if (!used) return;
    results({ local_buffer, used });
    used = 0;
  };
  auto add_datum=[&](int x){
    local_buffer[used] = x;
    ++used;
    if (used == 1024) send_data();
  };
  auto add_data=[&](gsl::span<int const> xs) {
    for (auto x:xs) add_datum(x);
  };
  for (int i = 0; i < 7+(1<<20); ++i) {
    add_datum(i);
  }
  send_data(); // any leftover
}

이제, std::function우리는 제로 오버 헤드없이 할당 환경에서이 일을하는 것처럼, 이것에 대한 비트 무겁습니다. 그래서 우리 function_view는 결코 할당하지 않는 것을 원합니다 .

또 다른 해결책은 다음과 같습니다.

std::function<void(std::function<void(int result, int other_result)>)> foo(int input);

콜백 foo을 가져와 호출하는 대신 콜백을 수행하는 함수를 반환합니다.

foo (7) ([&] (int result, int other_result) {/ * code * /}); 별도의 대괄호를 사용하여 입력 매개 변수에서 출력 매개 변수를 분리합니다.

variant코 루틴 foo을 사용하면 반환 유형의 변형 (또는 반환 유형)을 생성 할 수 있습니다. 구문은 아직 수정되지 않았으므로 예제를 제공하지 않습니다.

신호 및 슬롯 세계에서 신호 세트를 노출하는 기능 :

template<class...Args>
struct broadcaster;

broadcaster<int, int> foo();

foo비동기식으로 작동하고 완료되면 결과를 브로드 캐스트하는 을 만들 수 있습니다 .

이 줄 아래에는 다양한 파이프 라인 기술이 있는데, 여기서 함수는 어떤 기능을 수행하지 않고 데이터를 어떤 방식 으로든 연결하도록하고, 작업은 상대적으로 독립적입니다.

foo( int_source )( int_dest1, int_dest2 );

다음이 코드는하지 않습니다 때까지 아무것도 int_source를 제공하기 위해 정수가 있습니다. 이 수행 할 때, int_dest1그리고 int_dest2그 결과를 잡 시작합니다.


이 답변에는 다른 답변보다 더 많은 정보가 포함되어 있습니다! 특히 auto&&[result, other_result]=foo();튜플과 구조체를 모두 반환하는 함수 에 대한 정보 입니다. 감사!
jjmontes 19

특히 C ++ 11에 갇혀 있기 때문에이 철저한 답변에 감사드립니다. 따라서 다른 사람들이 제안하는보다 현대적인 솔루션을 사용할 수 없습니다.
GuyGizmo

5

반환 값에 구조체 또는 클래스를 사용하십시오. std::pair지금은 사용 이 가능하지만

  1. 나중에 더 많은 정보를 원한다고 결정하면 융통성이 없습니다.
  2. 반환되는 내용과 순서는 헤더의 함수 선언에서 명확하지 않습니다.

자체 문서화 멤버 변수 이름을 가진 구조를 반환하면 함수를 사용하는 사람에게는 버그가 덜 발생할 수 있습니다. 동료 모자를 잠시 착용하면 divide_result기능의 잠재적 사용자 인 2 초 후에 즉시 구조를 쉽게 이해할 수 있습니다. 출력 매개 변수 또는 신비한 쌍과 튜플을 사용하면 많은 시간이 걸리고 잘못 사용될 수 있습니다. 그리고 아마도 함수를 몇 번 사용한 후에도 여전히 올바른 인수 순서를 기억하지 못할 것입니다.


4

함수가 참조를 통해 값을 반환하는 경우 이론적으로 첫 번째 함수는 전역 적으로 액세스 가능한 변수에 전달 된 변수의 주소를 저장할 수 있고 하위 함수라고하는 함수는 컴파일러는 (1) 다른 함수를 호출하기 전에 레지스터의 값을 메모리에 다시 저장하고 (2) 이러한 호출 후 메모리에서 다시 필요할 때 다시 읽습니다.

참조로 돌아 오면 프로그램 최적화가 어려워집니다


4

여기에 C ++에서 여러 값 (두 개 이상의 값)을 반환하는 프로그램을 작성 중입니다. 이 프로그램은 c ++ 14 (G ++ 4.9.2)에서 실행 가능합니다. 프로그램은 계산기와 같습니다.

#  include <tuple>
# include <iostream>

using namespace std; 

tuple < int,int,int,int,int >   cal(int n1, int n2)
{
    return  make_tuple(n1/n2,n1%n2,n1+n2,n1-n2,n1*n2);
}

int main()
{
    int qut,rer,add,sub,mul,a,b;
    cin>>a>>b;
    tie(qut,rer,add,sub,mul)=cal(a,b);
    cout << "quotient= "<<qut<<endl;
    cout << "remainder= "<<rer<<endl;
    cout << "addition= "<<add<<endl;
    cout << "subtraction= "<<sub<<endl;
    cout << "multiplication= "<<mul<<endl;
    return 0;
}

따라서이 방법으로 함수에서 여러 값을 반환 할 수 있음을 명확하게 이해할 수 있습니다. std :: pair를 사용하면 2 개의 값만 반환되고 std :: tuple은 3 개 이상의 값을 반환 할 수 있습니다.


4
C ++ 14에서는 auto리턴 유형을 사용 cal하여이를 더욱 깨끗하게 만들 수도 있습니다 . (IMO).
sfjac

3

성공 / 오류 코드를 반환하는 함수의 패러다임을 고수하고 일을 균일하게 유지하기 때문에 이와 같은 함수에 out-val을 사용하는 경향이 있습니다.


2

대안은 배열, 생성기제어 역전을 포함 하지만 여기서는 적합하지 않습니다.

일부 (예 : 역사적 Win32의 Microsoft)는 스택에 누가 할당하고 어떻게 볼 것인지가 명확하고 구조의 확산을 줄이고 성공을 위해 별도의 반환 값을 허용하기 때문에 단순성을 위해 참조 매개 변수를 사용하는 경향이 있습니다.

"순수"프로그래머는 가정, 구조체를 선호하는 것입니다 (경우에 여기로) 다소의 함수에 의해 우연히 만진 것을 무언가보다 함수 값입니다. 더 복잡한 절차 또는 상태가있는 경우 클래스를 사용하지 않는 이유가 있다고 가정 할 때 참조를 사용합니다.


2

선호하는 방법이 없다고 말하면 응답으로 무엇을 할 것인지에 달려 있습니다. 결과가 추가 처리에 함께 사용될 예정이라면 구조가 의미가 있지만, 복합 명령문에서 함수를 사용하지 않는 한 개별 참조로 전달하는 경향이 있습니다.

x = divide( x, y, z ) + divide( a, b, c );

나는 종종 새로운 구조를 반환하는 복사 오버 헤드로 패스하는 대신 매개 변수 목록에서 참조로 '구조를 아웃'하기로 선택합니다 (그러나 이것은 작은 것들을 땀이 나고 있습니다).

void divide(int dividend, int divisor, Answer &ans)

매개 변수가 혼란 스럽습니까? 참조로 전송 된 매개 변수는 값이 변경 될 것임을 제안합니다 (const 참조가 아니라). 합리적인 이름으로도 혼란을 제거합니다.


1
다소 혼란 스럽다고 생각합니다. 호출하는 코드를 읽는 사람은 "divide (a, b, c);"를 보게됩니다. c가 서명을 찾을 때까지 c가 outval이라는 표시는 없습니다. 그러나 이것은이 질문에 대한 것이 아니라 비 const 참조 매개 변수에 대한 일반적인 두려움입니다.
Steve Jessop

2

여러 개의 반환 값을 가진 함수를 주장하는 이유는 무엇입니까? OOP를 사용하면 단일 반환 값과 아래와 같은 추가 "반환 값"을 갖는 정규 함수를 제공하는 클래스를 사용할 수 있습니다. 이점은 호출자가 추가 데이터 멤버를 볼 수있는 옵션을 선택할 수 있지만이를 수행 할 필요는 없다는 것입니다. 이 방법은 복잡한 데이터베이스 또는 네트워킹 호출에 선호되는 방법으로, 오류가 발생할 경우 많은 추가 반환 정보가 필요할 수 있습니다.

원래 질문에 대답하기 위해이 예제에는 대부분의 호출자가 필요할 수있는 몫을 반환하는 메소드가 있으며 메소드 호출 후에 나머지를 데이터 멤버로 가져올 수 있습니다.

class div{
   public:
      int remainder;

      int quotient(int dividend, int divisor){
         remainder = ...;
         return ...;
      }
};

1
이것이 비효율적 인 경우가 있다고 생각합니다. 예를 들어 여러 개의 반환 값을 생성하는 단일 for 루프가 있습니다. 해당 값을 별도의 함수로 분할하면 각 값에 대해 루프를 한 번 실행해야합니다.
jiggunjer

1
@jiggunjer 루프를 한 번 실행하고 여러 개의 반환 값을 별도의 클래스 데이터 멤버에 저장할 수 있습니다. 이것은 OOP 개념의 유연성을 강조합니다.
Roland

2

여러 값을 반환하는 대신 값 중 하나를 반환하고 필요한 기능에서 다른 값을 참조하십시오.

int divide(int a,int b,int quo,int &rem)

질문 자체에서 이것을 언급하지 않았습니까? 또한 내 답변 에서 이의 제기를 참조하십시오 .
프레드 라슨

1

부스트 튜플은 함수에서 하나 이상의 값을 반환하는 일반 시스템에서 선호하는 선택입니다.

가능한 예 :

include "boost/tuple/tuple.hpp"

tuple <int,int> divide( int dividend,int divisor ) 

{
  return make_tuple(dividend / divisor,dividend % divisor )
}

1

우리는 구조체 타입의 사용자 정의 변수 또는 그에 대한 포인터를 반환하도록 함수를 선언 할 수 있습니다. 그리고 구조체의 속성에 의해 C의 구조체는 비대칭 타입의 여러 값을 가질 수 있다는 것을 알고 있습니다 (즉, 하나의 int 변수, 4 개의 char 변수, 2 개의 float 변수 등).


1

반환 값이 몇 개인 경우 참조로 수행하지만 더 복잡한 유형의 경우 다음과 같이 수행 할 수도 있습니다.

static struct SomeReturnType {int a,b,c; string str;} SomeFunction()
{
  return {1,2,3,string("hello world")}; // make sure you return values in the right order!
}

"static"을 사용하여 리턴 유형의 범위를이 컴파일 단위로 제한하려면 임시 리턴 유형이어야합니다.

 SomeReturnType st = SomeFunction();
 cout << "a "   << st.a << endl;
 cout << "b "   << st.b << endl;
 cout << "c "   << st.c << endl;
 cout << "str " << st.str << endl;

이것은 확실히 가장 좋은 방법은 아니지만 효과가 있습니다.


-2

이러한 종류의 문제 해결책에 대한 전체 예는 다음과 같습니다.

#include <bits/stdc++.h>
using namespace std;
pair<int,int> solve(int brr[],int n)
{
    sort(brr,brr+n);

    return {brr[0],brr[n-1]};
}

int main()
{
    int n;
    cin >> n;
    int arr[n];
    for(int i=0; i<n; i++)
    {
        cin >> arr[i];
    }

    pair<int,int> o=solve(arr,n);
    cout << o.first << " " << o.second << endl;

    return 0;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.