对或元组值的名称别名引用

时间:2018-11-20 19:19:02

标签: c++ c++17 std-pair stdtuple structured-bindings

在重组某些代码时,返回带有2个值的结构时遇到“问题”。现在,这些确实应该以记录的效果命名。后来我想使用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会变得更加容易)。直接记忆是例如。元组是前向UB。由于变量已在使用中,因此直接结构化绑定也不可行。

我的问题是,不管可重用的部分(并且考虑到大小不应超过2个整数的大小),什么是更好或更简单的代码解决方案?

更新:在这种情况下,我最终只是做一个简单的结构,并暂时保留return。对于来这里的其他用户,有一个库建议可以增强,它似乎能够将任何结构转换为元组:https://github.com/apolukhin/magic_get/

3 个答案:

答案 0 :(得分:1)

您似乎对我来说问题太复杂了。如果您需要使用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);
  }
};

您也可以使用它一次将其分配给多个变量,尽管我强烈建议不要这样做。这容易出错,并导致代码变脆。 (例如,如果在下面的示例中颠倒deducttransfer的顺序,则说明您有bug,但是编译器不会给出警告或错误。)

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

这仍然很脆弱,但是至少现在,当您编写对decompose方法的调用时,您将获得智能感知,这将使模式更不容易出错。

答案 1 :(得分:0)

我只是选择:

struct Transaction
{
    int deducted;
    int transfered;
};

用法类似于:

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

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

Demo

答案 2 :(得分:0)

添加转换功能有效:

#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::getstd::tuple_size使其支持“类似元组”的绑定。