Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign multiple variables from a vector in c++? [duplicate]

Is it possible to use structured binding with vectors?

E.g.

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

Above code unfortunately doesn't work (under GCC), but maybe there's a different way (with structured binding) that allows to assign the first three values of a vector to three variables.

like image 930
BartekPL Avatar asked Nov 21 '25 08:11

BartekPL


2 Answers

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.

like image 180
ComicSansMS Avatar answered Nov 22 '25 20:11

ComicSansMS


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

like image 42
Quentin Avatar answered Nov 22 '25 20:11

Quentin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!