Работает ли структурированное связывание с std :: vector? - PullRequest
0 голосов
/ 28 июня 2018

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

* 1003 Е.Г. *

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

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

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

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

Смотрите его в прямом эфире на Колиру

0 голосов
/ 22 марта 2019

Не идеально, так как это более многословно, но вы также можете сделать:

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

(хотя vec [2] может выходить за пределы диапазона во время выполнения), так должно быть в случае вышеупомянутой структурированной привязки. То есть, почему бы не оставить пользователю возможность убедиться, что вектор имеет правильную длину во время выполнения, и выбросить исключение вне диапазона, если это не так? По сути, именно так мы используем векторы повсюду в языке.

0 голосов
/ 28 июня 2018

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

...