2017-05-03 48 views
61

我已经使用std::tie没有太多考虑。它的工作原理,所以我刚刚接受了: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如何创建一个临时?我觉得这更有趣,因为它是一个图书馆功能,而不是语言功能,所以它肯定是我们可以实现自己并理解的东西。

回答

94

为了阐明核心概念,我们将其简化为一个更基本的例子。虽然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 

下一步是看到什么发生在这些结构内部。 对于这一点,我创建了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 
} 

最后,我想摆脱的结构都在一起(当然,这不是相当于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

13

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

使用C++ 17,您几乎可以从头开始std::tie转而使用所谓的结构化绑定。他们也是这样做的(好吧,不一样,但它们有相同的净效果),尽管你需要输入更少的字符,它不需要库支持,而且你还有也有有能力引用if这恰好是你想要的。

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

如果最后一行编译我有点担心。它看起来像绑定一个非法的临时参考。 –

+0

@NirFriedman在这种情况下你不会获得终生延期吗? – Neil

+2

@Neil它必须是右值引用或常量左值引用。您不能将左值引用绑定到prvalue(临时)。尽管这已经是MSVC多年的“延伸”了。 –