性传播疾病是如何起作用的?

我在使用 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?我发现这个更有趣,因为它是一个库特性,而不是一个语言特性,所以它肯定是我们可以自己实现和理解的东西。

69860 次浏览

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

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

为了继续前进,我们需要知道的事情:

  • std::tie构造并返回一个引用元组。
  • std::tuple<int>std::tuple<int&>是两个完全不同的类,它们之间没有任何联系,除了它们是从同一个模板 std::tuple生成的。
  • Tuple 有一个 operator=,它接受一个不同类型(但数目相同)的 tuple,其中每个成员都被单独分配ーー来自 首选:

    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

下一步就是看看这些结构内部究竟发生了什么。 为此,我创建了 std::tuple<int>Tr取代基 std::tuple<int&>的2种类型的 T取代基,为我们的操作精简到最低限度:

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

这并没有以任何方式回答你的问题,但是我还是要把它贴出来,因为 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