возвращать различные конструкции диапазона из функции

Я пытаюсь получить представления диапазона, которые ведут себя как маски «истина-ложь». Чтобы выполнять логические операции, я хочу реализовать ands и ors масок. У меня есть рабочее время компиляции или:

struct make_or_mask_fn
{
    template<typename... Msks>
    auto operator()(Msks&&... msks) const
    {
        CONCEPT_ASSERT((Range<Msks>() || ...));
        return ranges::view::zip(std::forward<Msks>(msks)...) |
               ranges::view::transform(
                   [](auto&& range_item) -> bool {
                       return tuple_or(range_item);
                   });
    }

private:
    template<typename... T>
    static bool variable_length_or(const T... v)
    {
        return (v || ...);
    }
    template<typename... T, std::size_t... Idx>
    static bool tuple_or(const std::tuple<T...> t,
                         std::index_sequence<Idx...>)
    {
        return variable_length_or(std::get<Idx>(t)...);
    }
    template<typename... T>
    static bool tuple_or(const std::tuple<T...> t)
    {
        return tuple_or(t, std::index_sequence_for<T...>{});
    }
};
RANGES_INLINE_VARIABLE(make_or_mask_fn, make_or_masker)

который я могу назвать просто отлично

std::vector<bool> mask1 = ...
std::vector<bool> mask2 = ...
std::vector<bool> mask3 = ...
auto or_of_masks = make_or_masker(mask1, mask2, mask3);

Что это не может сделать в данный момент, так это построить или из ряда масок, которые неизвестны во время компиляции. Моя текущая попытка состоит в том, чтобы принять vector диапазонов, проверить его размер, а затем вызвать шаблон с переменным числом аргументов или ранее:

struct make_vector_or_mask_fn
{
    template<typename Msk>
    auto operator()(std::vector<Msk> msks)
        const // TODO const and reference types
    {
        CONCEPT_ASSERT(Range<Msk>());
        // todo return range with all true (an or of zero elements is true)
        assert(msks.size() != 0);
        if(msks.size() == 1)
            return or_ranges(msks[0]);
        if(msks.size() == 2)
            return or_ranges(msks[0], msks[1]);
        if(msks.size() == 3)
            return or_ranges(msks[0], msks[1], msks[2]);
        /// TODO: go until ... maybe 8 and recurse afterwards
    }
private:
    template<typename... Msks>
    static auto or_ranges(Msks&&... msks)
    {
        CONCEPT_ASSERT((Range<Msks>() || ...));
        return ranges::view::zip(std::forward<Msks>(msks)...) |
               ranges::view::transform(
                   [](auto&& range_item) -> bool {
                       return tuple_or(range_item);
                   });
    }
    template<typename... T>
    static bool variable_length_or(const T... v)
    {
        return (v || ...);
    }
    template<typename... T, std::size_t... Idx>
    static bool tuple_or(const std::tuple<T...> t,
                         std::index_sequence<Idx...>)
    {
        return variable_length_or(std::get<Idx>(t)...);
    }
    template<typename... T>
    static bool tuple_or(const std::tuple<T...> t)
    {
        return tuple_or(t, std::index_sequence_for<T...>{});
    }
};
RANGES_INLINE_VARIABLE(make_vector_or_mask_fn, make_vector_or_masker)

Это не компилируется со следующей ошибкой:

../include/range/v3/view/mask.hpp:221:25: error: 'auto' in return type deduced as 'ranges::v3::transform_view<ranges::v3::zip_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >, ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >,
  __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > > >, (lambda at ../include/range/v3/view/mask.hpp:188:32)>' here but deduced as 'ranges::v3::transform_view<ranges::v3::zip_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > > >,
  (lambda at ../include/range/v3/view/mask.hpp:188:32)>' in earlier return statement
                    return or_ranges(msks[0], msks[1]);
                    ^

Насколько я понимаю, это говорит мне о том, что мой or_ranges возвращает другой тип в зависимости от количества аргументов. (Я использую zip, который сохраняет информацию о том, что было застегнуто вместе).

Итак, мне интересно, как мне стереть то, что находится в диапазоне?


person pseyfert    schedule 29.08.2018    source источник
comment
Вас не волнует, что он в 3-10 раз медленнее, чем версия без стирания шрифта? Потому что это облегчает. Вы пробовали какое-либо стирание типа в rangesv3?   -  person Yakk - Adam Nevraumont    schedule 29.08.2018
comment
Это предназначено для входа в критичное по времени приложение. Если стирание шрифта имеет свою цену, я все равно попробую и профилирую, если смогу себе это позволить.   -  person pseyfert    schedule 30.08.2018


Ответы (1)


Верните ranges::v3::any_input_view < bool > вместо auto.

Это будет в 10 раз медленнее даже в оптимизированных сборках. Стирание шрифта стоит дорого.

Ручное решение, которое знает, что входной диапазон имеет длину, и получает данные в буферизованных фрагментах перед их раздачей, вероятно, могло бы приблизить производительность к стиранию без стирания типа. Однако я ожидаю, что это все равно будет заметно медленнее.

person Yakk - Adam Nevraumont    schedule 29.08.2018
comment
Пока одна придирка: это приводит к предупреждению ‘using any_input_view = struct ranges::v3::any_view<int, (ranges::v3::category)1, void ’ is deprecated: Use any_view<Ref, category::input> instead. [-Wdeprecated-declarations]. замена any_input_view на any_view работает. - person pseyfert; 31.08.2018