Повышение:: Кортежи по сравнению со Структурами для возвращаемых значений

44
задан Community 23 May 2017 в 12:16
поделиться

9 ответов

кортежи

я думаю, что соглашаюсь с Вами, что проблема с тем, какое положение соответствует тому, какая переменная может представить беспорядок. Но я думаю, что существует две стороны. Каждый , сторона вызова и другой сторона вызываемого :

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);

я думаю, что определенно получает премию за [1 125] четкость . Но обратите внимание, что необходимо все еще получить доступ к результату в той структуре, и результат не "раскрыт" на таблице, поскольку это имело место для выходных параметров и кортежа, используемого с tie.

я думаю, что важный пункт в эти дни должен сделать все максимально универсальным. Так, скажите, что у Вас есть функция, которая может распечатать кортежи. Можно просто сделать

cout << div(10, 3);

И отображать результат. Я думаю, что кортежи, с другой стороны, ясно побеждают для их универсальный природа. Делая это с div_result, необходимо перегрузить operator< < или потребность произвести каждого участника отдельно.

24
ответ дан Johannes Schaub - litb 26 November 2019 в 22:17
поделиться

Другая опция состоит в том, чтобы использовать карту Fusion Повышения (кодируйте непротестированный):

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 для получения дополнительной информации.

10
ответ дан Alastair 26 November 2019 в 22:17
поделиться

С кортежами можно использовать tie, который иногда довольно полезен: std::tr1::tie (quotient, remainder) = do_division ();. Это не настолько легко со структурами. Во-вторых, при использовании шаблона кода, иногда легче полагаться на пар, чем добавить еще одно определение типа для типа структуры.

И если типы отличаются, то пара/кортеж действительно не хуже, чем структура. Думайте, например pair<int, bool> readFromFile(), где интервал является количеством чтения байтов, и bool - был ли eof поражен. Добавление структуры в этом случае походит на излишество для меня, тем более, что нет никакой неоднозначности здесь.

5
ответ дан Anteru 26 November 2019 в 22:17
поделиться

Кортежи очень полезны на языках, таких как ML или Haskell.

В C++, их синтаксис делает их менее изящными, но может быть полезным в следующих ситуациях:

  • у Вас есть функция, которая должна возвратить больше чем один аргумент, но результат "локален" для вызывающей стороны и вызываемого; Вы не хотите определять структуру только для этого

  • , можно использовать функцию связи, чтобы сделать очень ограниченную форму сопоставления с образцом "а-ля ML", который более изящен, чем использование структуры для той же цели.

  • они идут с предопределенным < операторы, которые могут сэкономить время.

4
ответ дан 26 November 2019 в 22:17
поделиться

Я склонен использовать кортежи в сочетании с определениями типов к, по крайней мере, частично облегчают 'неназванный кортеж' проблема. Например, если у меня была структура сетки тогда:

//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);
3
ответ дан user21714 26 November 2019 в 22:17
поделиться

Предотвращает Ваш код, замусоренный многими определениями структуры. Для человека, пишущего код, и для другого использования его просто документ, каков каждый элемент в кортеже, вместо того, чтобы писать Вашим собственным людям структуры/создания, при поиске определения структуры легче.

2
ответ дан Keegan Carruthers-Smith 26 November 2019 в 22:17
поделиться

Кортежи будет легче записать - никакая потребность создать новую структуру для каждой функции, которая возвращает что-то. Документация о том, что идет, куда перейдет к функциональной документации, которая будет необходима так или иначе. Для использования функции, нужно будет прочитать функциональную документацию в любом случае, и кортеж будет объяснен там.

2
ответ дан Vilx- 26 November 2019 в 22:17
поделиться

Я согласовываю с Вами 100% Roddy.

Для возврата нескольких значений из метода у Вас есть несколько опций кроме кортежей, какой является лучшим, зависит от Вашего случая:

  1. Создание новой структуры. Это хорошо, когда несколько значений, которые Вы возвращаете, , имел отношение , и уместно создать новую абстракцию. Например, я думаю, что "divide_result" является хорошей общей абстракцией, и раздающий этот объект делает Ваш код намного более ясным, чем просто раздавание неназванного кортежа. Вы могли тогда создать методы, которые воздействуют на этот новый тип, преобразовывают его в другие числовые типы, и т.д.

  2. Используя параметры. Передайте несколько параметров ссылкой и возвратите несколько значений путем присвоения каждому параметра. Это является соответствующим, когда Ваш метод возвращает несколько не связанный сведения. Создание новой структуры в этом случае было бы излишеством, и с параметрами Вы подчеркиваете эту мысль, плюс каждый объект завоевывает репутацию, это заслуживает.

Кортежи являются Злыми.

-1
ответ дан Hermit 26 November 2019 в 22:17
поделиться

Одной из особенностей кортежей, которых нет в структурах, является их инициализация. Рассмотрим что-то вроде следующего:

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
}

Компилятор не может инициализировать "Tuple" с результатом make_tuple , и таким образом генерирует ошибку, которая позволяет вам указать правильные значения для третьего параметра.

Наконец, другое преимущество кортежей состоит в том, что они позволяют вам писать код, который выполняет итерацию по каждому значению. Это просто невозможно с использованием структуры.

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

template <typename Tuple_>
void incrementValues (Tuple_ & tuple) {
   // ...
   ++tuple.get_head ();
   incrementValues (tuple.get_tail ());
}
3
ответ дан 26 November 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: