C++ std::tie 是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43762651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:34:40  来源:igfitidea点击:

How does std::tie work?

c++c++11tuples

提问by bolov

I've used std::tiewithout giving much thought into it. It works so I've just accepted that:

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
}

But how does this black magicwork? How does a temporary created by std::tiechange aand b? I find this more interesting since it's a library feature, not a language feature, so surely it is something we can implement ourselves and understand.

但是这个黑魔法是如何运作的呢?如何通过std::tie更改a和创建临时b?我觉得这更有趣,因为它是一个库特性,而不是一个语言特性,所以它肯定是我们可以自己实现和理解的东西。

回答by bolov

In order to clarify the core concept, let's reduce it to a more basic example. Although std::tieis useful for functions returning (a tuple of) more values, we can understand it just fine with just one value:

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

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

Things we need to know in order to go forward:

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

  • std::tieconstructs and returns a tuple of references.
  • std::tuple<int>and std::tuple<int&>are 2 completely different classes, with no connection between them, other that they were generated from the same template, std::tuple.
  • tuple has an operator=accepting a tuple of different types (but same number), where each member is assigned individually—from cppreference:

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

    (3) For all i, assigns std::get<i>(other)to std::get<i>(*this).

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

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

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

The next step is to get rid of those functions that only get in your way, so we can transform our code to this:

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

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

The next step is to see exactly what happens inside those structures. For this, I create 2 types Tsubstituent for std::tuple<int>and Trsubstituent std::tuple<int&>, stripped down to the bare minimum for our operations:

下一步是查看这些结构内部究竟发生了什么。为此,我创建了 2 种类型的T取代基std::tuple<int>Tr取代基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
}

And finally, I like to get rid of the structures all together (well, it's not 100% equivalent, but it's close enough for us, and explicit enough to allow it):

最后,我喜欢把所有的结构都去掉(嗯,它不是 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
}

So basically, std::tie(a)initializes a data member reference to a. std::tuple<int>(24)creates a data member with value 24, and the assignment assigns 24 to the data member reference in the first structure. But since that data member is a reference bound to a, that basically assigns 24to a.

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

回答by Damon

This does not answer your question in any way, but let me post it anyway because C++17 is basically ready (with compiler support), so while wondering how the outdated stuff works, it is probably worth looking at how the current, and future, version of C++ works, too.

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

With C++17 you can pretty much scratch std::tiein favour of what is called structured bindings. They do the same (well, not the same, but they have the same net effect), although you need to type fewer characters, it does not need library support, and you alsohave the ability to take references, if that happens to be what you want.

使用 C++17,您几乎可以从头开始std::tie支持所谓的结构化绑定。他们做同样的事情(嗯,不一样,但他们有相同的净效果),虽然你需要输入更少的字符,它不需要库支持,而且你有能力获取引用,如果碰巧的话你想要什么。

(Note that in C++17 constructors do argument deduction, so make_tuplehas become somewhat superfluous, too.)

(请注意,在 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