Does structured binding work with std::vector?

前端 未结 3 861
隐瞒了意图╮
隐瞒了意图╮ 2020-12-15 03:40

Is it possible to use structured binding with vectors?

E.g.

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

Above code u

相关标签:
3条回答
  • 2020-12-15 03:55

    It's easy enough to create a basic wrapper over your vector that gives access to it like a tuple. Since there is indeed no way to retrieve a vector's size at compile time, this throws std::out_of_range if you attempt to destructure too short a vector. Unfortunately I don't know of a way to deduce the number of requested bindings, so that's explicit.

    Full code:

    #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.
    }
    

    Rvalue and const versions of vector_binder as well as better names are left as an exercise to the reader :)

    See it live on Coliru

    0 讨论(0)
  • 2020-12-15 04:00

    Structured binding only works if the structure is known at compile time. This is not the case for the vector.

    While you do know the structure of the individual elements, you do not know the number of elements, and that is what you are trying to decompose on in your question. Similarly, you can only use structured bindings on array types where the size is known at compile time. Consider:

    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;
    }
    

    The first two will work, but the last line will fail to compile, because the size of arr3 is not known at compile time. Try it on godbolt.

    0 讨论(0)
  • 2020-12-15 04:14

    Not ideal since it's more verbose but you can also do:

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

    I do not agree with the notion that not knowing the number of elements of a container should prevent structured binding to it's elements. My reasoning is that since the following does not throw a compile time error:

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

    (even though vec[2] might be out of range at run-time), so should be the case for the above structured binding. Meaning, why not leave it to the user to make sure vector has the correct length at runtime, and throw an out of range exception if that is not the case? That is essentially how we use vectors everywhere else in the language.

    0 讨论(0)
提交回复
热议问题