【问题标题】:Structured binding reference with tuple of reference带有引用元组的结构化绑定引用
【发布时间】:2020-10-02 15:06:55
【问题描述】:

Structured binding Case2 in cppreference 有点难以理解。基本上,我想澄清一下这些情况

int x = 1;
double y = 2.0;
auto [a, b] = std::forward_as_tuple(x, y);   //a, b are both reference, why?
auto&& [c, d] = std::forward_as_tuple(x, y); //What's the difference of this and above?
auto&& [e, f] = std::tuple{x, y};  //why are NOT e, f rvalue references? Resharper shows them as value type not reference type

如果有一些函数返回引用元组,我如何使用结构化绑定进行复制?

std::tuple<int&, double&> f;
auto [x, y] = f(); //But I want a copy from the reference, how?

【问题讨论】:

    标签: c++ c++17 structured-bindings


    【解决方案1】:

    std::forward_as_tuple(x, y) 给你一个tuple&lt;int&amp;, double&amp;&gt;。绑定到其中的类型是int&amp;double&amp;(与绑定到tuple&lt;int, double&gt; 的类型相同的是intdouble)。基本上:

    auto [a, b] = std::forward_as_tuple(x, y);
    auto&& [c, d] = std::forward_as_tuple(x, y);
    

    表现得好像:

    auto __e = std::forward_as_tuple(x, y);
    using __E = remove_reference_t<decltype(__e)>;
    tuple_element_t<0, __E>&& a = std::get<0>(std::move(__e));
    tuple_element_t<1, __E>&& b = std::get<1>(std::move(__e));
    
    auto&& __f = std::forward_as_tuple(x, y);
    using __F = remove_reference_t<decltype(__f)>;
    tuple_element_t<0, F>&& c = std::get<0>(std::move(__f));
    tuple_element_t<1, F>&& d = std::get<1>(std::move(__f));
    

    所以a 是对int&amp; 的右值引用,c 是对double&amp; 的右值引用,所以分别是int&amp;double&amp;。这个特殊的公式(我特别称它为引用的引用,而不是只称它为int&amp;)是必要的,因为decltype(name) 其中name 是一个结构化绑定为您提供了referenced 类型,这就是为什么decltype(a) 会给你int&amp;

    上面还显示了[a, b][c, d] 案例之间的区别:autoauto&amp;&amp; 声明适用于我们正在解构的未命名对象。它不会影响绑定本身

    这个案例:

    auto&& [e, f] = std::tuple{x, y};
    

    不提供参考,因为它解压到:

    auto&& __g = std::tuple{x, y};
    using __G = remove_reference_t<decltype(__g)>;
    tuple_element_t<0, G>&& e = std::get<0>(std::move(__g));
    tuple_element_t<1, G>&& f = std::get<1>(std::move(__g));
    

    所以e 是对int 的右值引用,这意味着decltype(e)int,而不是int&amp;


    如果有一些函数返回引用元组,我如何使用结构化绑定进行复制?

    您无法使用结构化绑定制作副本。结构化绑定是关于解构一个对象,它根本不是关于改变任何东西。如果要复制,则必须手动进行:

    std::tuple<int&, double&> f = /* ... */;
    std::tuple<int, double> actual_copy = f;
    auto& [x, y] = actual_copy; 
    

    在上述情况下,因为被解构的底层对象是左值引用 (auto&amp;),这在技术上使绑定本身成为左值引用而不是右值引用——虽然我不确定这是否真的是一个有意义的区别。

    【讨论】:

    • 为什么 auto&amp;&amp; [e, f] = std::tuple{x, y}; 解包到 auto&amp;&amp; __g = std::forward_as_tuple(x, y); ?为什么tuple_element_t&lt;0, decltype(__g)&gt;&amp;&amp; e 评估为int 而不是int&amp;&amp;
    • @szppeter 第一个是错字对不起。 tuple_element_t&lt;0, decltype(__g)&gt;inte 的实际 类型int&amp;&amp;,但这不是 decltype(e) 给你的 - 它给你引用的类型,int&amp;&amp; 的引用类型是 int
    • tuple_element_t&lt;0, decltype(__g)&gt;&amp;&amp;std::tuple{x, y} 情况下无法编译
    • @szppeter 是的,只是缺少一个remove_reference_t
    【解决方案2】:

    如果有一些函数返回引用元组,我如何使用结构化绑定进行复制?

    也许像下面这样的辅助函数会很有用:

    template <class Tuple, size_t... indices>
    constexpr auto
    tuple_copy_impl(const Tuple& tuple, std::index_sequence<indices...>) {
       return std::tuple{std::get<indices>(tuple)...};
    }
    
    template <class Tuple>
    constexpr auto
    tuple_copy(const Tuple& tuple) {
        constexpr auto s = std::tuple_size_v<Tuple>;
        using I = std::make_index_sequence<s>;
        return tuple_copy_impl<Tuple>(tuple, I{});
    }
    
    auto [x, y] = tuple_copy(f());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 2012-08-06
      • 2020-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多