std :: tie是如何工作的?

时间:2017-05-03 14:17:56

标签: c++ c++11 tuples

我已经使用了std::tie而没有仔细考虑它。它有效,所以我接受了:

auto test()
{
   int a, b;
   std::tie(a, b) = std::make_tuple(2, 3);
   // a is now 2, b is now 3
   return a + b; // 5
}

但这个黑魔法如何运作? std::tie创建的临时更改如何更改ab?我发现这更有趣,因为它是一个库功能,而不是语言功能,所以我们可以自己实现并理解它。

2 个答案:

答案 0 :(得分:124)

为了澄清核心概念,让我们将其简化为一个更基本的例子。虽然std::tie对返回(一个元组)更多值的函数很有用,但我们只用一个值就可以理解它:

int a;
std::tie(a) = std::make_tuple(24);
return a; // 24

为了向前发展我们需要知道的事情:

  • std::tie构造并返回一个引用元组。
  • std::tuple<int>std::tuple<int&>是两个完全不同的类,它们之间没有任何关联,另外它们是从同一个模板std::tuple生成的。
  • 元组有operator=接受不同类型(但编号相同)的元组,其中每个成员都是单独分配的 - 来自cppreference

    template< class... UTypes >
    tuple& operator=( const tuple<UTypes...>& other );
    
         

    (3)对于所有i,将std::get<i>(other)分配给std::get<i>(*this)

下一步是摆脱那些只会妨碍你的功能,所以我们可以将代码转换为:

int a;
std::tuple<int&>{a} = std::tuple<int>{24};
return a; // 24

下一步是确切了解这些结构中发生了什么。 为此,我为Tstd::tuple<int>取代基Tr创建了2种std::tuple<int&>取代基,为我们的操作剥离了最低限度:

struct T { // substituent for std::tuple<int>
    int x;
};

struct Tr { // substituent for std::tuple<int&>
    int& xr;

    auto operator=(const T& other)
    {
       // std::get<I>(*this) = std::get<I>(other);
       xr = other.x;
    }
};

auto foo()
{
    int a;
    Tr{a} = T{24};

    return a; // 24
}

最后,我喜欢一起摆脱这些结构(好吧,它不是100%相同,但它对我们足够接近,并且足够明确允许它):

auto foo()
{
    int a;

    { // block substituent for temporary variables

    // Tr{a}
    int& tr_xr = a;

    // T{24}
    int t_x = 24;

    // = (asignement)
    tr_xr = t_x;
    }

    return a; // 24
}

基本上,std::tie(a)将数据成员引用初始化为astd::tuple<int>(24)创建值为24的数据成员,赋值为第一个结构中的数据成员引用分配24。但由于该数据成员是绑定到a的引用,因此基本上将24分配给a

答案 1 :(得分:22)

这不会以任何方式回答你的问题,但是让我发布它,因为C ++ 17基本上已经准备就绪(有编译器支持),所以在想知道过时的东西是如何工作的时候,可能值得看看如何当前和未来的C ++版本也有效。

使用C ++ 17,您可以使用std::tie来支持所谓的结构化绑定。他们做同样的事情(好吧,不一样,但它们具有相同的净效果),虽然你需要输入更少的字符,它不需要库支持,你有能力参考。

(请注意,在C ++ 17中,构造函数会进行参数推导,因此make_tuple也变得多余了。)

int a, b;
std::tie(a, b) = std::make_tuple(2, 3);

// C++17
auto  [c, d] = std::make_tuple(4, 5);
auto  [e, f] = std::tuple(6, 7);
std::tuple t(8,9); auto& [g, h] = t; // not possible with std::tie