문제

나는 내 주위는 튜플(감사@litb),그리고 일반적인 제안에 대한 그들의 사용은 기능을 위해 반환>1 값입니다.

이것은 뭔가가 나는 일반적으로 사용하는 구조체에 대한,그리고 내가 이해할 수 없다는 장점을 갖는 튜플 이 경우-그것 보다는 오류가 발생하기 쉬운 접근 방식에 대한 말기다.

대출 예, 나이

struct divide_result {
    int quotient;
    int remainder;
};

를 사용하여 튜플 했

typedef boost::tuple<int, int> divide_result;

그러나지 않고 읽는 코드는 함수 호출하고(또는 의견을 경우,당신이 충분히 그들을 신뢰하)당신은 아무 생각이 없는가 지수는 그 반대의 경우도 마찬가지입니다.그것 보다는 오히려 좋아하...

struct divide_result {
    int results[2]; // 0 is quotient, 1 is remainder, I think
};

...는 없을 것으로 가득 채우는 신뢰.

그래서 무엇 의 장점 튜플을 통해 구조체의 보상에 대한 모?

도움이 되었습니까?

해결책

튜플

나는 어떤 위치가 어떤 변수가 혼란을 불러 일으킬 수 있는지에 해당하는 문제에 동의한다고 생각합니다. 그러나 나는 양면이 있다고 생각합니다. 하나는입니다 전화면 그리고 다른 하나는 칼리 쪽:

int remainder; 
int quotient;
tie(quotient, remainder) = div(10, 3);

나는 그것이 우리가 얻은 것을 분명하다고 생각하지만, 한 번에 더 많은 값을 반환해야한다면 혼란 스러울 수 있습니다. 발신자의 프로그래머가 문서를 찾아 보면 div, 그는 어떤 위치가 무엇인지 알고 효과적인 코드를 작성할 수 있습니다. 경험상, 나는 한 번에 4 개 이상의 값을 반환하지 않는다고 말할 것입니다. 그 이상으로 구조물을 선호하십시오.

출력 매개 변수

물론 출력 매개 변수도 사용할 수 있습니다.

int remainder; 
int quotient;
div(10, 3, &quotient, &remainder);

이제는 튜플이 출력 매개 변수보다 얼마나 나은지를 보여줍니다. 우리는 입력을 혼합했습니다 div 이점을 얻지 못하면 출력으로. 더 나쁜 것은, 우리는 그 코드의 독자가 의심의 여지가있는 것에 대해 실제 반환 값 div 이다. 거기 ~이다 출력 매개 변수가 유용한 경우 멋진 예. 내 생각에, 반환 값이 이미 가져 왔고 튜플이나 구조물로 변경할 수 없기 때문에 다른 방법이 없을 때만 사용해야합니다. operator>> 리턴 값이 이미 스트림에 예약되어 있기 때문에 출력 매개 변수를 사용하는 위치에 대한 좋은 예입니다. operator>> 전화. 연산자와 관련이없고 컨텍스트가 명확하지 않은 경우, 호출 측면에서 객체가 실제로 출력 매개 변수로 사용되며 적절한 경우 주석을 사용한다는 신호를 사용하여 포인터를 사용하는 것이 좋습니다.

구조물을 반환합니다

세 번째 옵션은 구조물을 사용하는 것입니다.

div_result d = div(10, 3);

나는 그것이 상을 수상한 것 같아요 명료도. 그러나 해당 구조물 내에서 결과에 액세스해야하며 결과는 출력 매개 변수와 사용한 튜플의 경우와 같이 테이블에 "베어 맨"이 아닙니다. tie.

요즘 주요 요점은 가능한 한 일반적인 모든 것을 만드는 것입니다. 따라서 튜플을 인쇄 할 수있는 기능이 있다고 가정 해 봅시다. 당신은 그냥 할 수 있습니다

cout << div(10, 3);

결과를 표시하십시오. 반대편에 튜플이 분명히 그들의 변하기 쉬운 자연. div_result로이를 수행하려면 연산자 <<을 과부하해야하거나 각 멤버를 별도로 출력해야합니다.

다른 팁

또 다른 옵션은 사용하는 향상 융합 지도(코드로 검증되지 않은):

struct quotient;
struct remainder;

using boost::fusion::map;
using boost::fusion::pair;

typedef map<
    pair< quotient, int >,
    pair< remainder, int >
> div_result;

당신은에 액세스할 수 있는 결과를 상대적으로 직관적으로:

using boost::fusion::at_key;

res = div(x, y);
int q = at_key<quotient>(res);
int r = at_key<remainder>(res);

다른 이점이 있습니다 너무 등의 기능을 반복 이 분야의 지도 등이 있습니다.보 doco 자세한 내용은.

튜플을 사용하면 사용할 수 있습니다 tie, 때로는 매우 유용합니다. std::tr1::tie (quotient, remainder) = do_division ();. 스트러크는 그리 쉽지 않습니다. 둘째, 템플릿 코드를 사용할 때 구조물 유형에 대한 또 다른 typedef를 추가하는 것보다 쌍에 의존하는 것이 더 쉽습니다.

그리고 유형이 다르면 쌍/튜플은 실제로 구조물보다 나쁘지 않습니다. 예를 들어 생각하십시오 pair<int, bool> readFromFile(), int가 바이트 판 읽기 수이고 bool은 eof가 적중되었는지 여부입니다. 이 경우 구조물을 추가하는 것은 특히 모호성이 없기 때문에 나에게 과잉처럼 보입니다.

튜플은 ML 또는 Haskell과 같은 언어에서 매우 유용합니다.

C ++에서는 구문이 덜 우아하지만 다음 상황에서 유용 할 수 있습니다.

  • 하나 이상의 인수를 반환 해야하는 함수가 있지만 결과는 발신자와 칼리에게 "로컬"입니다. 당신은 이것을위한 구조를 정의하고 싶지 않습니다.

  • 타이 함수를 사용하여 동일한 목적으로 구조를 사용하는 것보다 우아합니다.

  • 그들은 사전 정의 된 <연산자와 함께 제공되며, 이는 시간을 절약 할 수 있습니다.

나는 'nameless 튜플'문제를 적어도 부분적으로 완화하기 위해 typedefs와 함께 튜플을 사용하는 경향이 있습니다. 예를 들어 그리드 구조가 있다면 다음과 같습니다.

//row is element 0 column is element 1
typedef boost::tuple<int,int> grid_index;

그런 다음 지명 된 유형을 다음과 같이 사용합니다.

grid_index find(const grid& g, int value);

이것은 다소 고안된 예이지만 대부분의 시간은 가독성, 명시성 및 사용 용이성 사이의 행복한 매체에 부딪친다고 생각합니다.

또는 예에서 :

//quotient is element 0 remainder is element 1
typedef boost:tuple<int,int> div_result;
div_result div(int dividend,int divisor);

Structs와 함께 가지고 있지 않은 튜플의 특징 중 하나는 초기화에 있습니다. 다음과 같은 것을 고려하십시오.

struct A
{
  int a;
  int b;
};

당신이 쓰지 않는 한 make_tuple 동등한 또는 생성자 그런 다음이 구조를 입력 매개 변수로 사용하려면 먼저 임시 객체를 작성해야합니다.

void foo (A const & a)
{
  // ...
}

void bar ()
{
   A dummy = { 1, 2 };
   foo (dummy);
}

그러나 그다지 나쁘지는 않지만 유지 보수가 어떤 이유로 든 새로운 멤버를 구조물에 추가하는 경우를 봅니다.

struct A
{
  int a;
  int b;
  int c;
};

집계 초기화 규칙은 실제로 코드가 변경없이 계속 컴파일 될 것임을 의미합니다. 따라서 컴파일러의 도움 없이이 구조물의 모든 사용법을 검색하고 업데이트해야합니다.

이것을 튜플과 대조하십시오.

typedef boost::tuple<int, int, int> Tuple;
enum {
  A
  , B
  , C
};

void foo (Tuple const & p) {
}

void bar ()
{
  foo (boost::make_tuple (1, 2));  // Compile error
}

컴파일러는 결과로 "튜플"을 시작할 수 없습니다. make_tuple, 따라서 세 번째 매개 변수의 올바른 값을 지정할 수있는 오류를 생성합니다.

마지막으로, 튜플의 또 다른 장점은 각 값을 반복하는 코드를 작성할 수 있다는 것입니다. 이것은 단순히 구조물을 사용하여 불가능합니다.

void incrementValues (boost::tuples::null_type) {}

template <typename Tuple_>
void incrementValues (Tuple_ & tuple) {
   // ...
   ++tuple.get_head ();
   incrementValues (tuple.get_tail ());
}

많은 구조물 정의로 코드가 흩어지지 않도록합니다. 코드를 작성하는 사람이 더 쉽고 코드를 사용하는 것이 더 쉽고, 튜플의 각 요소가 자신의 구조물을 작성하는 것이 아니라 사람들이 구조물 정의를 찾는 대신 튜플의 각 요소가 무엇인지 문서화 할 때 더 쉽습니다.

튜플은 쓰기가 더 쉬울 것입니다. 무언가를 반환하는 모든 기능에 대해 새 구조물을 만들 필요가 없습니다. 어쨌든 어디로 가는지에 대한 문서는 어쨌든 필요할 것입니다. 함수를 사용하려면 어떤 경우에도 함수 문서를 읽어야하며 튜플이 설명됩니다.

100% Roddy에 동의합니다.

메소드에서 여러 값을 반환하려면 튜플 이외의 옵션이 있습니다.

  1. 새로운 구조물 만들기. 반환하는 여러 값이 관련된, 그리고 새로운 추상화를 만드는 것이 적절합니다. 예를 들어, 나는 "divide_result"가 좋은 일반적인 추상화라고 생각하며,이 엔티티를 전달하면 이름이없는 튜플을 전달하는 것보다 코드가 훨씬 더 명확 해집니다. 그런 다음이 새로운 유형에서 작동하는 메소드를 작성하고 다른 숫자 유형으로 변환 할 수 있습니다.

  2. "out"매개 변수 사용. 여러 매개 변수를 참조별로 전달하고 각 매개 변수에 할당하여 여러 값을 반환하십시오. 메소드가 여러 가지를 반환 할 때 적절합니다 관련이 없습니다 정보의 조각. 이 경우 새 구조물을 생성하는 것은 과잉이며, 매개 변수를 사용하면이 점을 강조하고 각 항목은 가치가있는 이름을 얻습니다.

튜플은 사악합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top