Работает ли структурированное связывание с std :: vector?

Можно ли использовать структурированное связывание с векторами?

Например

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

Над кодом, к сожалению, не работает (под GCC), но, возможно, существует другой способ (со структурированной привязкой), который позволяет назначить первые три значения вектора для трех переменных.

Ответ 1

Структурированное связывание работает только в том случае, если структура известна во время компиляции. Это не относится к 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 не известен во время компиляции. Попробуйте это на кресте.

Ответ 2

Достаточно легко создать базовую оболочку над вашим вектором, которая дает доступ к ней, как кортеж. Поскольку в момент компиляции нет способа получить векторный размер, это вызывает std::out_of_range если вы 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.
}

Rvalue и const версии vector_binder а также лучшие имена остаются в качестве упражнения для читателя :)

Смотрите, как живут на Coliru