Диапазоны V3 на молнии с авто и структурированными креплениями - PullRequest
1 голос
/ 03 мая 2020

Я хотел бы иметь возможность использовать диапазоны C ++, чтобы упростить логику кода c с помощью архивирования контейнеров, а не явной индексации в них. Я могу заставить это работать с подробным лямбда-аргументом, но я бы скорее попытался сделать его более простым / обобщенным с большим количеством auto.

const int n = ...;
std::vector<float> a(n), b(n), c(n);

...initialize a and b...

// This works
ranges::for_each(
    ranges::views::zip(a, b, c),
    [](const std::tuple<float&, float&, float&>& v)
    {
        const auto& [a, b, c] = v;
        c = a + b; 
        std::cout << typeid(v).name(); // NSt3__15tupleIJRfS1_S1_EEE
    }
);

// This fails
ranges::for_each(
    ranges::views::zip(a, b, c),
    [](const auto& v)
    {
        const auto& [a, b, c] = v;
        // c = a + b; 
        std::cout << typeid(v).name(); // N6ranges12common_tupleIJRfS1_S1_EEE
    }
);

В документации Ranges-v3 написано следующее:

views::zip

Если даны N диапазоны, вернуть новый диапазон, где Mth элемент является результатом вызова make_tuple на элементах Mth всех диапазонов N .

Это заставляет меня думать, что я должен быть в состоянии преобразовать ranges::common_tuple в std::tuple, и я посмотрел на * publi c членов и нашел:

std::tuple< Ts... > const & base() const noexcept

Однако это также не компилируется:

const auto& [a, b, c] = v.base();
// error: no member named 'base' in 'std::__1::tuple<float, float, float>'

Но когда я печатаю typeid(v), это не std::tuple; это ranges::common_tuple. Возможно ли здесь то, что я пытаюсь сделать с auto выводом типа? (лягушка компилятор, если это имеет значение)

1 Ответ

3 голосов
/ 03 мая 2020

Короткий ответ: не используйте const, если вам на самом деле не нужно const. Вы хотите что-то изменить, так почему const? Это прекрасно работает:

ranges::for_each(
    ranges::views::zip(a, b, c),
    [](auto&& v)
    {
        auto&& [a, b, c] = v;
        c = a + b; 
    }
);

Как и короче:

for (auto&& [a, b, c] : ranges::views::zip(a, b, c)) {
    c = a + b;
}

Причина, по которой у вас перерывы, довольно тонкая. По сути, ranges::for_each ограничен indirectly_unary_invocable, для которого требуется все:

        invocable<F &, iter_value_t<I> &> &&
        invocable<F &, iter_reference_t<I>> &&
        invocable<F &, iter_common_reference_t<I>> &&

Таким образом, ваша лямбда создается со всеми тремя этими типами. Один из этих типов (iter_value_t<I>&) - tuple<float, float, float>&. Поэтому, когда вы делаете структурированное связывание с const auto&, тип каждого из связываний будет const float. Вот почему это не присваивается - но это верно только для этого конкретного экземпляра c (который в любом случае вызывается не во время выполнения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...