结构化绑定是否与std :: vector一起使用?

Bar*_*kPL 24 c++ vector pattern-matching c++17 structured-bindings

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

例如

std::vector<int> vec{1, 2, 3};
auto [a, b, c] = vec;
Run Code Online (Sandbox Code Playgroud)

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

Com*_*sMS 30

结构化绑定仅在编译时已知结构时才有效.事实并非如此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;
}
Run Code Online (Sandbox Code Playgroud)

前两个将工作,但最后一行将无法编译,因为arr3在编译时不知道大小.在godbolt上尝试一下.


Que*_*tin 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.
}
Run Code Online (Sandbox Code Playgroud)

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

在Coliru上看到它

  • @everyone - `vector_binder`是一个引用类型(la`tring_view`).我们拥有自己的副本并不重要,它仍然指向底层向量,而绑定是对底层向量的引用.我们正在做`auto __e = dissect <2>(v); __e.get <0>()= 5;`这实际上是`v [0] = 5;` (3认同)
  • 如果不对结构化绑定使用`auto &`,你确定应该修改`v [0]`吗?如果用数组替换向量(并相应地更改代码),`v [0]`不会被`a = 5`语句修改. (2认同)
  • @StoryTeller 哦,是的,我想就是这样。`auto&amp;` 上的引用适用于 `vector_binder` 本身,无论如何,元素都是通过它的引用来访问的。您必须删除“get”返回类型上的“&amp;”才能使其正常运行。 (2认同)
  • @Quentin但是如果你删除“get”上的“&amp;”,你将无法绑定到引用。我很高兴真正了解是什么使这段代码的行为与“std::array”或“std::tuple”不同。 (2认同)

poo*_*a13 11

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

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];
Run Code Online (Sandbox Code Playgroud)

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