I have a function foo()
, it returns a vector
with three elements.
I want specify three variables to capture the elements at index 0
, 1
, 2
. Obviously I know the normal code, like
auto vec = foo();
a = vec[0]; b = vec[1]; c = vec[2];
But I want an elegant format, just like Python, as follows:
auto& [a,b,c] = foo();
Is there any way to implement it?
auto [a,b,c] = foo();
(structured binding) would be possible for a tuple-like type such as std::tuple
or std::array
, but it's not possible for std::vector
.
However, you can use structured bindings syntax with a slight workaround:
template <typename T>
std::array<T, 3> first_three(const std::vector<T>& vec) {
if (vec.size() < 3) {
throw std::invalid_argument("vec must contain at least three elements");
}
return { vec[0], vec[1], vec[2] };
}
auto [a, b, c] = first_three(foo());
That being said, if you're only interested in the first three elements, perhaps foo()
should return a std::array<T, 3>
or some other tuple-like type. Perhaps std::vector<T>
was the wrong type to use in the first place.
first_three
only works for copyable types in its current state. You can add an rvalue overload to avoid copying:
template <typename T>
std::array<T, 3> first_three(std::vector<T>&& vec) {
if (vec.size() < 3) {
throw std::invalid_argument("vec must contain at least three elements");
}
return { std::move(vec[0]), std::move(vec[1]), std::move(vec[2]) };
}
There are ways to have only one function as well, but it would be quite annoying to implement. For starters, std::vector::operator[]
has no rvalue overloads and you don't have std::forward_like
in C++17, so forwarding the elements out of the vector is a bit tricky.