【问题标题】:return different range constructs from function从函数返回不同的范围结构
【发布时间】:2018-08-29 10:32:49
【问题描述】:

我试图获得表现得像真假面具的范围视图。为了进行逻辑运算,我想实现掩码的 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 保留了压缩在一起的知识)。

所以我想知道,如何键入擦除范围内的内容?

【问题讨论】:

  • 你关心它是否比非类型擦除版本慢 3x-10x 吗?因为这样更容易。您是否尝试过 rangev3 中的任何类型擦除?
  • 这意味着进入一个时间关键的应用程序。如果类型擦除是有代价的,如果我负担得起的话,我仍然会试一试和配置文件。

标签: c++ c++17 type-erasure range-v3


【解决方案1】:

返回ranges::v3::any_input_view &lt; bool &gt; 而不是auto。

即使在优化的构建中,这也会慢 10 倍。类型擦除很昂贵。

知道输入范围有一个长度并在分配数据之前以缓冲块的形式获取数据的手动解决方案可能会使性能更接近非类型擦除。不过,我希望它仍然会明显变慢。

【讨论】:

  • 到目前为止的一个挑剔:这会导致警告‘using any_input_view = struct ranges::v3::any_view&lt;int, (ranges::v3::category)1, void ’ is deprecated: Use any_view&lt;Ref, category::input&gt; instead. [-Wdeprecated-declarations]。用any_view 替换any_input_view 似乎可行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多