Имя псевдонима для парных или кортежных значений - PullRequest
0 голосов
/ 20 ноября 2018

При реструктуризации некоторого кода я столкнулся с «проблемой» при возврате структуры с двумя значениями.Теперь они действительно должны быть названы для задокументированного эффекта.Позже я захотел использовать tie, поэтому я изменил структуру на наследование от std::pair и просто установил ссылки.Теперь это на самом деле работает нормально, но вы заметите, что моя структура имеет размер 24, а не 8 по сравнению с парой.

#include <tuple>


struct Transaction : public std::pair<int, int> {
    using pair::pair;

  int& deducted = first;
  int& transfered = second;
};
//static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));//commenting in this line will fail compilation

Transaction makeTheTransaction();

void test(int& deduct, int& transfer) {
    std::tie(deduct, transfer) = makeTheTransaction(); 
}

Возможно, очевидный метод состоит в том, чтобы перейти к функциям-членам, однако для этого случая это тоже слишком «шаблонный» пример (тогда становится проще не использовать tie позже).Прямой memcpy, например.кортеж прямо вперед UB.Прямое структурированное связывание также невозможно, поскольку переменные уже используются.

Мой вопрос заключается в том, что является лучшим или минимальным решением для кода, не учитывающим повторно используемые части (и учитывая, что размер не должен превышать размер2 дюйма)?

ОБНОВЛЕНИЕ: В этом случае я просто создал простую структуру и временно удерживал return.Для других пользователей, пришедших сюда, есть предложение для библиотеки, которое может преобразовать любую структуру в кортеж: https://github.com/apolukhin/magic_get/

Ответы [ 3 ]

0 голосов
/ 20 ноября 2018

Кажется, ты слишком усложняешь мне проблему.Если вам нужно использовать std::tie, вы можете просто использовать его.Нет необходимости изменять вашу структуру:

struct Transaction
{
  int deducted;
  int transferred;
};

// later...

auto t = std::tie(transaction.deducted, transaction.transferred);

Если вы часто используете этот шаблон, вы можете обернуть его небольшим вспомогательным методом:

struct Transaction
{
  int deducted;
  int transferred;

  auto to_tuple() const
  {
    return std::tie(deducted, transferred);
  }
};

Вы также можете использоватьэто назначить нескольким переменным одновременно, хотя я настоятельно не рекомендую это.Это подвержено ошибкам и приводит к хрупкому коду.(Например, если вы поменяете порядок deduct и transfer в приведенном ниже примере, вы получите ошибку, но компилятор не выдаст предупреждение или ошибку.)

void test(int& deduct, int& transfer)
{
  std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}

Редактировать: Если подумать ...

Если цель здесь - просто разложить структуру на переменные, вы можете сделать это напрямую и избежать использования пар или кортежей:

struct Transaction
{
  int deducted;
  int transferred;

  void decompose(int* deducted_, int* transferred_)
  {
    *deducted_ = deducted;
    *transferred_ = transferred;
  }
};

void test(int& deduct, int& transfer)
{
  makeTheTransaction().decompose(&deduct, &transfer);
}

Это все еще хрупко, но, по крайней мере, теперь вы получите intellisense, когда напишите вызов метода decompose, что сделает шаблон немного менее подверженным ошибкам.

0 голосов
/ 20 ноября 2018

Добавление функции преобразования работает:

#include <tuple>

struct Transaction {
    std::pair<int, int> data_;

    operator std::tuple<int &, int &> () {
        return std::tie(data_.first, data_.second);
    }
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));

Transaction makeTheTransaction() {
    return Transaction();
}

void test(int& deduct, int& transfer) {
    std::tie(deduct, transfer) = makeTheTransaction();
}

Я не думаю, что это вызовет какие-либо проблемы со временем жизни при использовании с std :: tie.

Transaction не работает со структурированной привязкой с двумя идентификаторами.Но вы можете сделать так, чтобы он поддерживал "кортежоподобное" связывание, специализируя std::get и std::tuple_size для него.

0 голосов
/ 20 ноября 2018

Я бы просто пошел с:

struct Transaction
{
    int deducted;
    int transfered;
};

С использованием, аналогичным:

Transaction makeTheTransaction() { return {4, 2}; }

int main()
{
    auto [deduct, transfer] = makeTheTransaction(); 
    std::cout << deduct << transfer << std::endl;
}

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...