结构化绑定可以与std :: vector一起使用吗?

时间:2018-06-28 07:43:07

标签: c++ vector pattern-matching c++17 structured-bindings

是否可以对向量使用结构化绑定?

例如

std::vector<int> vec{1, 2, 3};
auto [a, b, c] = vec;

不幸的是,以上代码在GCC下不起作用,但是也许有另一种方式(结构化绑定)可以将向量的前三个值分配给三个变量。

3 个答案:

答案 0 :(得分:29)

结构化绑定仅在编译时已知结构的情况下起作用。 vector并非如此。

虽然您知道各个元素的结构,但是却不知道元素的数量,这就是您要在问题中尝试分解的内容。同样,您只能对在编译时知道大小的数组类型使用结构化绑定。考虑:

void f(std::array<int, 3> arr1,
       int (&arr2)[3],
       int (&arr3)[])
{
    auto [a1,b1,c1] = arr1;
    auto [a2,b2,c2] = arr2;
    auto [a3,b3,c3] = arr3;
}

前两个可以工作,但最后一行将无法编译,因为arr3的大小在编译时未知。 Try it on godbolt

答案 1 :(得分:21)

在向量上创建一个基本包装器就很容易了,它可以像元组一样访问它。由于确实没有办法在编译时检索向量的大小,因此,如果您尝试解构向量太短,则会抛出std::out_of_range。不幸的是,我不知道一种推断请求的绑定数的方法,因此很明显。

完整代码:

#include <string>
#include <vector>
#include <iostream>

template <class T, std::size_t N>
struct vector_binder {
    std::vector<T> &vec;

    template <std::size_t I>
    T &get() {
        return vec.at(I);
    }
};

namespace std {
    template<class T, std::size_t N>
    struct tuple_size<vector_binder<T, N>>
    : std::integral_constant<std::size_t, N> { };

    template<std::size_t I, std::size_t N, class T>
    struct tuple_element<I, vector_binder<T, N>> { using type = T; };
}

template <std::size_t N, class T>
auto dissect(std::vector<T> &vec) {
    return vector_binder<T, N>{vec};
}

int main() {
    std::vector<int> v{1, 2, 3};
    auto [a, b] = dissect<2>(v);

    a = 5;
    std::cout << v[0] << '\n'; // Has changed v through a as expected.
}

vector_binder的右值和const版本以及更好的名称留给读者练习:)

See it live on Coliru

答案 2 :(得分:0)

不理想,因为它比较冗长,但您也可以这样做:

auto [a, b, c] = array<int, 3>({vec[0], vec[1], vec[2]});

我不同意这样的观点,即不知道容器的元素数量会阻止对其元素的结构化绑定。我的理由是,由于以下内容不会引发编译时错误:

auto a = vec[0];
auto b = vec[1];
auto c = vec[2];

(即使vec [2]在运行时可能超出范围),上述结构化绑定也应如此。意思是,为什么不让用户确保矢量在运行时具有正确的长度,如果不是,则抛出超出范围的异常?本质上,这就是我们在语言的其他任何地方使用向量的方式。