【问题标题】:Structured binding and tie()结构化绑定和 tie()
【发布时间】:2018-03-30 12:28:53
【问题描述】:

鉴于这些声明:

int a[3] {10,20,30};
std::tuple<int,int,int> b {11,22,33};

我可以使用结构化绑定声明来解码ab

auto [x1,y1,z1] = a;
auto [x2,y2,z2] = b;

但是如果x1y1等已经存在,我该怎么办?

std::tie(x1,y1,z1) = a;  // ERROR
std::tie(x2,y2,z2) = b;  // OK

这适用于b,但不适用于a。是否有类似的简单构造适用于a,还是我必须分别获取a[0]a[1]a[2]

【问题讨论】:

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


    【解决方案1】:

    没有。

    结构化绑定具有处理数组和某些其他类型的特定语言规则。 tie() 专门是一个tuple&lt;T&amp;...&gt;,只能从另一个tuple&lt;U&amp;...&gt; 分配。


    使用数组的情况,您可以编写一个函数来将该数组转换为对它的引用元组:

    template <typename T, size_t N, size_t... Is>
    auto as_tuple_impl(T (&arr)[N], std::index_sequence<Is...>) {
        return std::forward_as_tuple(arr[Is]...);
    }
    
    template <typename T, size_t N>
    auto as_tuple(T (&arr)[N]) {
        return as_tuple_impl(arr, std::make_index_sequence<N>{});
    }
    
    std::tie(x1, y1, z1) = as_tuple(a); // ok
    

    或者,如果您知道有多少绑定(无论如何您都必须这样做),您可以使用结构化绑定作为返回元组。但是你必须指定尺寸并为每个写一个案例:

    template <size_t I, typename T>
    auto as_tuple(T&& tuple) {
        if constexpr (I == 1) {
            auto&& [a] = std::forward<T>(tuple);
            return std::forward_as_tuple(a);
        } else if constexpr (I == 2) {
            auto&& [a, b] = std::forward<T>(tuple);
            return std::forward_as_tuple(a, b);
        } else if constexpr (I == 3) {
            // etc.
        }
    }
    
    std::tie(x1, y1, z1) = as_tuple<3>(a); // ok
    

    【讨论】:

    • 在第二种情况下,您不能在get 上使用 SFINAE 删除显式大小吗?
    • @PasserBy get 对于std::array 不是 SFINAE 友好的,它不是为原始数组定义的(对吗?),它绝对不适用于具有所有公共成员的类型。
    • 再看一些over-the-top machinery,这是可能的。
    • @PasserBy Clever 但是...您可以对非聚合类型使用结构化绑定 :-)
    【解决方案2】:

    只是为了好玩...模拟类似于

    的语法
    std::tie(x1,y1,z1) = a;
    

    您可以编写一个结构体来包装一个指针数组,并为相应的数组使用operator=()

    template <typename T, std::size_t ... Is>
    struct ptrArray<T, std::index_sequence<Is...>>
     {
       std::array<T*, sizeof...(Is)> ap;
    
       auto & operator= (T (&arr)[sizeof...(Is)])
        {
          ((*ap[Is] = arr[Is]), ...);
    
          return *this;
        }
     };
    

    以及这个结构的生成函数

    template <typename T0, typename ... Ts>
    ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
       makePtrArray (T0 & t0, Ts & ... ts)
     { return { { { &t0, &ts... } } }; }
    

    makePtrArray(x1, y1, z1) = a;
    

    有效。

    以下是一个完整的工作示例

    #include <array>
    #include <iostream>
    #include <type_traits>
    
    template <typename, typename>
    struct ptrArray;
    
    template <typename T, std::size_t ... Is>
    struct ptrArray<T, std::index_sequence<Is...>>
     {
       std::array<T*, sizeof...(Is)> ap;
    
       auto & operator= (T (&arr)[sizeof...(Is)])
        {
          ((*ap[Is] = arr[Is]), ...);
    
          return *this;
        }
     };
    
    template <typename T0, typename ... Ts>
    ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
       makePtrArray (T0 & t0, Ts & ... ts)
     { return { { { &t0, &ts... } } }; }
    
    int main ()
     {
       int x1, y1, z1;
       int a[3] {10,20,30};
    
       makePtrArray(x1, y1, z1) = a;
    
       std::cout << x1 << ' ' << y1 << ' ' << z1 << std::endl;
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-03
      • 1970-01-01
      • 2017-02-07
      • 1970-01-01
      • 2017-05-15
      • 2017-04-02
      • 1970-01-01
      相关资源
      最近更新 更多