C++ Range:view all - 1

本文详细分析了C++ Range v3库中all_view的实现原理,探讨了其如何根据不同输入类型(如view、容器或非容器类型)转换为view,重点关注了all_fn::from_range_函数的重载机制,以及ref_view和make_subrange的使用。文章还解释了pipeable概念和ViewableRange、ForwardingRange_等要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

view::all

include\range\v3\view\all.hpp

        struct all_fn : pipeable<all_fn>
        {
        private:
            /// If it's a view already, pass it though.
            template<typename T>
            static auto from_range_(T && t, std::true_type, detail::ignore_t,
                                    detail::ignore_t)
            {
                return static_cast<T &&>(t);
            }

            /// If it is container-like, turn it into a view, being careful
            /// to preserve the Sized-ness of the range.
            template<typename T>
            static auto from_range_(T && t, std::false_type, std::true_type,
                                    detail::ignore_t)
            {
                return ranges::view::ref(t);
            }

            /// Not a view and not an lvalue? If it's a ForwardingRange_, then
            /// return a subrange holding the range's begin/end.
            template<typename T>
            static auto from_range_(T && t, std::false_type, std::false_type,
                                    std::true_type)
            {
                return make_subrange(static_cast<T &&>(t));
            }

        public:
            template<typename T>
            auto CPP_fun(operator())(T && t)(const requires ViewableRange<T>)
            {
                return all_fn::from_range_(static_cast<T &&>(t),
                                           meta::bool_<View<uncvref_t<T>>>{},
                                           std::is_lvalue_reference<T>{},
                                           meta::bool_<ForwardingRange_<T>>{});
            }

            template<typename T>
            RANGES_DEPRECATED("Passing a reference_wrapper to view::all is deprecated.")
            auto operator()(std::reference_wrapper<T> ref) const
                -> CPP_ret(ref_view<T>)( //
                    requires Range<T &>)
            {
                return ranges::view::ref(ref.get());
            }
        };

分析all的实现,他的思路是operator()(T && t)调用重载了的all_fn::from_range_: 通过meta::bool_<View<uncvref_t>>{}和std::is_lvalue_reference{}实现重载。
深入理解这个函数的几个障碍是:

  1. detail::ignore_t
  2. ranges::view::ref
  3. make_subrange
  4. pipeable<all_fn>的实现
  5. ViewableRange和requires Range<T &>的要求

ignore_t

include\range\v3\range_fwd.hpp

  struct ignore_t
  {
      ignore_t() = default;
      template<typename T>
      constexpr ignore_t(T &&) noexcept
      {}
      template<typename T>
      constexpr ignore_t const & operator=(T &&) const noexcept
      {
          return *this;
      }
  };

ignore_t实现了三个构造函数:1. 默认构造函数,2. 移动构造函数:允许任何类型转变为ignore_t; 3. 移动赋值函数:允许任何类型赋值为ignore_t. 这里的参数并没有指定名字。 2和3并没有指定参数的名字,所以,这个ignore_t允许把任何 类型赋值给他。

ranges::view::ref

  struct ref_fn
  {
      template<typename Rng>
      constexpr auto operator()(Rng & rng) const noexcept
          -> CPP_ret(ref_view<Rng>)( //
              requires Range<Rng>)
      {
          return ref_view<Rng>(rng);
      }
      template<typename Rng>
      void operator()(Rng const && rng) const = delete;
  };

  /// \relates const_fn
  /// \ingroup group-views
  RANGES_INLINE_VARIABLE(view<ref_fn>, ref)

返回的是ref_view, 所以,主要看ref_view的实现:

ref_view

  /// \cond
  namespace _ref_view_
  {
      struct adl_hook
      {};

      template<typename Rng>
      constexpr iterator_t<Rng> begin(ref_view<Rng> && rng) noexcept(
          noexcept(rng.begin()))
      {
          return rng.begin();
      }
      template<typename Rng>
      constexpr iterator_t<Rng> begin(ref_view<Rng> const && rng) noexcept(
          noexcept(rng.begin()))
      {
          return rng.begin();
      }
      template<typename Rng>
      constexpr sentinel_t<Rng> end(ref_view<Rng> && rng) noexcept(noexcept(rng.end()))
      {
          return rng.end();
      }
      template<typename Rng>
      constexpr sentinel_t<Rng> end(ref_view<Rng> const && rng) noexcept(
          noexcept(rng.end()))
      {
          return rng.end();
      }
  } // namespace _ref_view_
  /// \endcond

_ref_view_实现了对range begin和end的调用,相当于一个proxy类。

ref_view

  /// \addtogroup group-views
  /// @{
  template<typename Rng>
  struct ref_view
    : view_interface<ref_view<Rng>, range_cardinality<Rng>::value>
    , private _ref_view_::adl_hook
  {
  
  }

ref依赖于ref_view,而ref_view的实现依赖于view_interface. 所以,要先分析一下view interface。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值