Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:09:59

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-present
0005 //
0006 //  Use, modification and distribution is subject to the
0007 //  Boost Software License, Version 1.0. (See accompanying
0008 //  file LICENSE_1_0.txt or copy at
0009 //  http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 // Project home: https://github.com/ericniebler/range-v3
0012 //
0013 
0014 #ifndef RANGES_V3_VIEW_TRANSFORM_HPP
0015 #define RANGES_V3_VIEW_TRANSFORM_HPP
0016 
0017 #include <iterator>
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 #include <meta/meta.hpp>
0022 
0023 #include <range/v3/range_fwd.hpp>
0024 
0025 #include <range/v3/algorithm/max.hpp>
0026 #include <range/v3/algorithm/min.hpp>
0027 #include <range/v3/functional/bind_back.hpp>
0028 #include <range/v3/functional/indirect.hpp>
0029 #include <range/v3/functional/invoke.hpp>
0030 #include <range/v3/iterator/operations.hpp>
0031 #include <range/v3/range/access.hpp>
0032 #include <range/v3/range/primitives.hpp>
0033 #include <range/v3/range/traits.hpp>
0034 #include <range/v3/utility/move.hpp>
0035 #include <range/v3/utility/semiregular_box.hpp>
0036 #include <range/v3/utility/static_const.hpp>
0037 #include <range/v3/view/adaptor.hpp>
0038 #include <range/v3/view/all.hpp>
0039 #include <range/v3/view/view.hpp>
0040 
0041 #include <range/v3/detail/prologue.hpp>
0042 
0043 namespace ranges
0044 {
0045     /// \cond
0046     namespace detail
0047     {
0048         constexpr cardinality transform2_cardinality(cardinality c1, cardinality c2)
0049         {
0050             return c1 >= 0 || c2 >= 0
0051                        ? (c1 >= 0 && c2 >= 0 ? (c1 < c2 ? c1 : c2) : finite)
0052                        : c1 == finite || c2 == finite
0053                              ? finite
0054                              : c1 == unknown || c2 == unknown ? unknown : infinite;
0055         }
0056 
0057         // clang-format off
0058         /// \concept iter_transform_1_readable_
0059         /// \brief The \c iter_transform_1_readable_ concept
0060         template(typename Fun, typename Rng)(
0061         concept (iter_transform_1_readable_)(Fun, Rng),
0062             regular_invocable<Fun &, iterator_t<Rng>> AND
0063             regular_invocable<Fun &, copy_tag, iterator_t<Rng>> AND
0064             regular_invocable<Fun &, move_tag, iterator_t<Rng>> AND
0065             common_reference_with<
0066                 invoke_result_t<Fun &, iterator_t<Rng>> &&,
0067                 invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> &> AND
0068             common_reference_with<
0069                 invoke_result_t<Fun &, iterator_t<Rng>> &&,
0070                 invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&> AND
0071             common_reference_with<
0072                 invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&,
0073                 invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> const &>
0074         );
0075         /// \concept iter_transform_1_readable
0076         /// \brief The \c iter_transform_1_readable concept
0077         template<typename Fun, typename Rng>
0078         CPP_concept iter_transform_1_readable =
0079             CPP_concept_ref(detail::iter_transform_1_readable_, Fun, Rng);
0080 
0081         /// \concept iter_transform_2_readable_
0082         /// \brief The \c iter_transform_2_readable_ concept
0083         template(typename Fun, typename Rng1, typename Rng2)(
0084         concept (iter_transform_2_readable_)(Fun, Rng1, Rng2),
0085             regular_invocable<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> AND
0086             regular_invocable<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
0087             regular_invocable<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
0088             common_reference_with<
0089                 invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
0090                 invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> &> AND
0091             common_reference_with<
0092                 invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
0093                 invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&> AND
0094             common_reference_with<
0095                 invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&,
0096                 invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> const &>
0097         );
0098         /// \concept iter_transform_2_readable
0099         /// \brief The \c iter_transform_2_readable concept
0100         template<typename Fun, typename Rng1, typename Rng2>
0101         CPP_concept iter_transform_2_readable =
0102             CPP_concept_ref(detail::iter_transform_2_readable_, Fun, Rng1, Rng2);
0103         // clang-format on
0104     } // namespace detail
0105     /// \endcond
0106 
0107     /// \addtogroup group-views
0108     /// @{
0109     template<typename Rng, typename Fun>
0110     struct iter_transform_view : view_adaptor<iter_transform_view<Rng, Fun>, Rng>
0111     {
0112     private:
0113         friend range_access;
0114         RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
0115         template<bool Const>
0116         using use_sentinel_t =
0117             meta::bool_<!common_range<meta::const_if_c<Const, Rng>> ||
0118                         single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>>;
0119 
0120         template<bool IsConst>
0121         struct adaptor : adaptor_base
0122         {
0123         private:
0124             friend struct adaptor<!IsConst>;
0125             using CRng = meta::const_if_c<IsConst, Rng>;
0126             using fun_ref_ = semiregular_box_ref_or_val_t<Fun, IsConst>;
0127             RANGES_NO_UNIQUE_ADDRESS fun_ref_ fun_;
0128 
0129         public:
0130             using value_type =
0131                 detail::decay_t<invoke_result_t<Fun &, copy_tag, iterator_t<CRng>>>;
0132             adaptor() = default;
0133             adaptor(fun_ref_ fun)
0134               : fun_(std::move(fun))
0135             {}
0136             template(bool Other)(
0137                 requires IsConst AND CPP_NOT(Other)) //
0138             adaptor(adaptor<Other> that)
0139               : fun_(std::move(that.fun_))
0140             {}
0141 
0142             // clang-format off
0143             auto CPP_auto_fun(read)(iterator_t<CRng> it)(const)
0144             (
0145                 return invoke(fun_, it)
0146             )
0147             auto CPP_auto_fun(iter_move)(iterator_t<CRng> it)(const)
0148             (
0149                 return invoke(fun_, move_tag{}, it)
0150             )
0151             // clang-format on
0152         };
0153 
0154         adaptor<false> begin_adaptor()
0155         {
0156             return {fun_};
0157         }
0158         template(bool Const = true)(
0159             requires Const AND range<meta::const_if_c<Const, Rng>> AND
0160                 detail::iter_transform_1_readable<Fun const,
0161                                                   meta::const_if_c<Const, Rng>>)
0162         adaptor<Const> begin_adaptor() const
0163         {
0164             return {fun_};
0165         }
0166         meta::if_<use_sentinel_t<false>, adaptor_base, adaptor<false>> end_adaptor()
0167         {
0168             return {fun_};
0169         }
0170         template(bool Const = true)(
0171             requires Const AND range<meta::const_if_c<Const, Rng>> AND
0172                     detail::iter_transform_1_readable<Fun const,
0173                                                       meta::const_if_c<Const, Rng>>)
0174         meta::if_<use_sentinel_t<Const>, adaptor_base, adaptor<Const>> end_adaptor() const
0175         {
0176             return {fun_};
0177         }
0178 
0179     public:
0180         iter_transform_view() = default;
0181         iter_transform_view(Rng rng, Fun fun)
0182           : iter_transform_view::view_adaptor{std::move(rng)}
0183           , fun_(std::move(fun))
0184         {}
0185         CPP_auto_member
0186         constexpr auto CPP_fun(size)()(
0187             requires sized_range<Rng>)
0188         {
0189             return ranges::size(this->base());
0190         }
0191         CPP_auto_member
0192         constexpr auto CPP_fun(size)()(const //
0193             requires sized_range<Rng const>)
0194         {
0195             return ranges::size(this->base());
0196         }
0197     };
0198 
0199     template<typename Rng, typename Fun>
0200     struct transform_view : iter_transform_view<Rng, indirected<Fun>>
0201     {
0202         transform_view() = default;
0203         transform_view(Rng rng, Fun fun)
0204           : iter_transform_view<Rng, indirected<Fun>>{std::move(rng),
0205                                                       indirect(std::move(fun))}
0206         {}
0207     };
0208 
0209 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
0210     template(typename Rng, typename Fun)(
0211         requires copy_constructible<Fun>)
0212     transform_view(Rng &&, Fun)
0213         -> transform_view<views::all_t<Rng>, Fun>;
0214 #endif
0215 
0216     template<typename Rng1, typename Rng2, typename Fun>
0217     struct iter_transform2_view
0218       : view_facade<iter_transform2_view<Rng1, Rng2, Fun>,
0219                     detail::transform2_cardinality(range_cardinality<Rng1>::value,
0220                                                    range_cardinality<Rng2>::value)>
0221     {
0222     private:
0223         friend range_access;
0224         RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
0225         Rng1 rng1_;
0226         Rng2 rng2_;
0227         using difference_type_ =
0228             common_type_t<range_difference_t<Rng1>, range_difference_t<Rng2>>;
0229 
0230         static constexpr cardinality my_cardinality = detail::transform2_cardinality(
0231             range_cardinality<Rng1>::value, range_cardinality<Rng2>::value);
0232 
0233         template<bool>
0234         struct cursor;
0235 
0236         template<bool Const>
0237         struct sentinel
0238         {
0239         private:
0240             friend struct cursor<Const>;
0241             sentinel_t<meta::const_if_c<Const, Rng1>> end1_;
0242             sentinel_t<meta::const_if_c<Const, Rng2>> end2_;
0243 
0244         public:
0245             sentinel() = default;
0246             sentinel(meta::const_if_c<Const, iter_transform2_view> * parent,
0247                      decltype(ranges::end))
0248               : end1_(end(parent->rng1_))
0249               , end2_(end(parent->rng2_))
0250             {}
0251             template(bool Other)(
0252                 requires Const AND CPP_NOT(Other)) //
0253             sentinel(sentinel<Other> that)
0254               : end1_(std::move(that.end1_))
0255               , end2_(std::move(that.end2_))
0256             {}
0257         };
0258 
0259         template<bool Const>
0260         struct cursor
0261         {
0262         private:
0263             using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
0264             using R1 = meta::const_if_c<Const, Rng1>;
0265             using R2 = meta::const_if_c<Const, Rng2>;
0266             fun_ref_ fun_;
0267             iterator_t<R1> it1_;
0268             iterator_t<R2> it2_;
0269 
0270         public:
0271             using difference_type = difference_type_;
0272             using single_pass = meta::or_c<(bool)single_pass_iterator_<iterator_t<R1>>,
0273                                            (bool)single_pass_iterator_<iterator_t<R2>>>;
0274             using value_type =
0275                 detail::decay_t<invoke_result_t<meta::const_if_c<Const, Fun> &, copy_tag,
0276                                                 iterator_t<R1>, iterator_t<R2>>>;
0277 
0278             cursor() = default;
0279             template<typename BeginEndFn>
0280             cursor(meta::const_if_c<Const, iter_transform2_view> * parent,
0281                    BeginEndFn begin_end)
0282               : fun_(parent->fun_)
0283               , it1_(begin_end(parent->rng1_))
0284               , it2_(begin_end(parent->rng2_))
0285             {}
0286             template(bool Other)(
0287                 requires Const AND CPP_NOT(Other)) //
0288             cursor(cursor<Other> that)
0289               : fun_(std::move(that.fun_))
0290               , it1_(std::move(that.end1_))
0291               , it2_(std::move(that.end2_))
0292             {}
0293             // clang-format off
0294             auto CPP_auto_fun(read)()(const)
0295             (
0296                 return invoke(fun_, it1_, it2_)
0297             )
0298                 // clang-format on
0299                 void next()
0300             {
0301                 ++it1_;
0302                 ++it2_;
0303             }
0304             CPP_member
0305             auto equal(cursor const & that) const //
0306                 -> CPP_ret(bool)(
0307                     requires forward_range<Rng1> && forward_range<Rng2>)
0308             {
0309                 // By returning true if *any* of the iterators are equal, we allow
0310                 // transformed ranges to be of different lengths, stopping when the first
0311                 // one reaches the last.
0312                 return it1_ == that.it1_ || it2_ == that.it2_;
0313             }
0314             bool equal(sentinel<Const> const & s) const
0315             {
0316                 // By returning true if *any* of the iterators are equal, we allow
0317                 // transformed ranges to be of different lengths, stopping when the first
0318                 // one reaches the last.
0319                 return it1_ == s.end1_ || it2_ == s.end2_;
0320             }
0321             CPP_member
0322             auto prev() //
0323                 -> CPP_ret(void)(
0324                     requires bidirectional_range<R1> && bidirectional_range<R2>)
0325             {
0326                 --it1_;
0327                 --it2_;
0328             }
0329             CPP_member
0330             auto advance(difference_type n) -> CPP_ret(void)(
0331                 requires random_access_range<R1> && random_access_range<R2>)
0332             {
0333                 ranges::advance(it1_, n);
0334                 ranges::advance(it2_, n);
0335             }
0336             CPP_member
0337             auto distance_to(cursor const & that) const //
0338                 -> CPP_ret(difference_type)(
0339                     requires sized_sentinel_for<iterator_t<R1>, iterator_t<R1>> &&
0340                         sized_sentinel_for<iterator_t<R2>, iterator_t<R2>>)
0341             {
0342                 // Return the smallest distance (in magnitude) of any of the iterator
0343                 // pairs. This is to accommodate zippers of sequences of different length.
0344                 difference_type d1 = that.it1_ - it1_, d2 = that.it2_ - it2_;
0345                 return 0 < d1 ? ranges::min(d1, d2) : ranges::max(d1, d2);
0346             }
0347             // clang-format off
0348             auto CPP_auto_fun(move)()(const)
0349             (
0350                 return invoke(fun_, move_tag{}, it1_, it2_)
0351             )
0352             // clang-format on
0353         };
0354 
0355         template<bool Const>
0356         using end_cursor_t = meta::if_c<
0357             common_range<meta::const_if_c<Const, Rng1>> &&
0358                 common_range<meta::const_if_c<Const, Rng2>> &&
0359                 !single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng1>>> &&
0360                 !single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng2>>>,
0361             cursor<Const>, sentinel<Const>>;
0362 
0363         cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
0364         {
0365             return {this, ranges::begin};
0366         }
0367         end_cursor_t<simple_view<Rng1>() && simple_view<Rng2>()> end_cursor()
0368         {
0369             return {this, ranges::end};
0370         }
0371         template(bool Const = true)(
0372             requires Const AND range<meta::const_if_c<Const, Rng1>> AND
0373                 range<meta::const_if_c<Const, Rng2>> AND
0374                 detail::iter_transform_2_readable< //
0375                     Fun const, //
0376                     meta::const_if_c<Const, Rng1>, //
0377                     meta::const_if_c<Const, Rng2>>)
0378         cursor<true> begin_cursor() const
0379         {
0380             return {this, ranges::begin};
0381         }
0382         template(bool Const = true)(
0383             requires Const AND range<meta::const_if_c<Const, Rng1>> AND
0384                 range<meta::const_if_c<Const, Rng2>> AND
0385                 detail::iter_transform_2_readable< //
0386                     Fun const, //
0387                     meta::const_if_c<Const, Rng1>, //
0388                     meta::const_if_c<Const, Rng2>>)
0389         end_cursor_t<Const> end_cursor() const
0390         {
0391             return {this, ranges::end};
0392         }
0393         template<typename Self>
0394         static constexpr auto size_(Self & self)
0395         {
0396             using size_type = common_type_t<range_size_t<Rng1>, range_size_t<Rng2>>;
0397             return ranges::min(static_cast<size_type>(ranges::size(self.rng1_)),
0398                                static_cast<size_type>(ranges::size(self.rng2_)));
0399         }
0400 
0401         template<bool B>
0402         using R1 = meta::invoke<detail::dependent_<B>, Rng1>;
0403         template<bool B>
0404         using R2 = meta::invoke<detail::dependent_<B>, Rng2>;
0405 
0406     public:
0407         iter_transform2_view() = default;
0408         constexpr iter_transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
0409           : fun_(std::move(fun))
0410           , rng1_(std::move(rng1))
0411           , rng2_(std::move(rng2))
0412         {}
0413         CPP_member
0414         static constexpr auto size() //
0415             -> CPP_ret(std::size_t)(
0416                 requires (my_cardinality >= 0))
0417         {
0418             return static_cast<std::size_t>(my_cardinality);
0419         }
0420         template(bool True = true)(
0421             requires (my_cardinality < 0) AND sized_range<Rng1 const> AND
0422             sized_range<Rng2 const> AND
0423             common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
0424             constexpr auto size() const
0425         {
0426             return size_(*this);
0427         }
0428         template(bool True = true)(
0429             requires (my_cardinality < 0) AND sized_range<Rng1> AND sized_range<Rng2> AND
0430             common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
0431             constexpr auto size()
0432         {
0433             return size_(*this);
0434         }
0435     };
0436 
0437     template<typename Rng1, typename Rng2, typename Fun>
0438     struct transform2_view : iter_transform2_view<Rng1, Rng2, indirected<Fun>>
0439     {
0440         transform2_view() = default;
0441         constexpr transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
0442           : iter_transform2_view<Rng1, Rng2, indirected<Fun>>{std::move(rng1),
0443                                                               std::move(rng2),
0444                                                               indirect(std::move(fun))}
0445         {}
0446     };
0447 
0448     namespace views
0449     {
0450         struct iter_transform_base_fn
0451         {
0452             template(typename Rng, typename Fun)(
0453                 requires viewable_range<Rng> AND input_range<Rng> AND
0454                     copy_constructible<Fun> AND
0455                     detail::iter_transform_1_readable<Fun, Rng>)
0456             constexpr iter_transform_view<all_t<Rng>, Fun> //
0457             operator()(Rng && rng, Fun fun) const
0458             {
0459                 return {all(static_cast<Rng &&>(rng)), std::move(fun)};
0460             }
0461 
0462             template(typename Rng1, typename Rng2, typename Fun)(
0463                 requires viewable_range<Rng1> AND input_range<Rng1> AND
0464                     viewable_range<Rng2> AND input_range<Rng2> AND
0465                     copy_constructible<Fun> AND
0466                     common_with<range_difference_t<Rng1>, range_difference_t<Rng1>> AND
0467                     detail::iter_transform_2_readable<Fun, Rng1, Rng2>)
0468             constexpr iter_transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
0469             operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
0470             {
0471                 return {all(static_cast<Rng1 &&>(rng1)),
0472                         all(static_cast<Rng2 &&>(rng2)),
0473                         std::move(fun)};
0474             }
0475         };
0476 
0477         struct iter_transform_fn : iter_transform_base_fn
0478         {
0479             using iter_transform_base_fn::operator();
0480 
0481             template<typename Fun>
0482             constexpr auto operator()(Fun fun) const
0483             {
0484                 return make_view_closure(
0485                     bind_back(iter_transform_base_fn{}, std::move(fun)));
0486             }
0487         };
0488 
0489         /// \relates iter_transform_fn
0490         /// \ingroup group-views
0491         RANGES_INLINE_VARIABLE(iter_transform_fn, iter_transform)
0492 
0493         // Don't forget to update views::for_each whenever this set
0494         // of concepts changes
0495         // clang-format off
0496         /// \concept transformable_range_
0497         /// \brief The \c transformable_range_ concept
0498         template(typename Rng, typename Fun)(
0499         concept (transformable_range_)(Rng, Fun),
0500             regular_invocable<Fun &, range_reference_t<Rng>> AND
0501             (!std::is_void<indirect_result_t<Fun &, iterator_t<Rng>>>::value)
0502         );
0503         /// \concept transformable_range
0504         /// \brief The \c transformable_range concept
0505         template<typename Rng, typename Fun>
0506         CPP_concept transformable_range =
0507             viewable_range<Rng> && input_range<Rng> &&
0508             copy_constructible<Fun> &&
0509             CPP_concept_ref(views::transformable_range_, Rng, Fun);
0510 
0511         /// \concept transformable_ranges_
0512         /// \brief The \c transformable_ranges_ concept
0513         template(typename Rng1, typename Rng2, typename Fun)(
0514         concept (transformable_ranges_)(Rng1, Rng2, Fun),
0515             regular_invocable<Fun &, range_reference_t<Rng1>, range_reference_t<Rng2>> AND
0516             (!std::is_void<
0517                 indirect_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>>>::value)
0518         );
0519         /// \concept transformable_ranges
0520         /// \brief The \c transformable_ranges concept
0521         template<typename Rng1, typename Rng2, typename Fun>
0522         CPP_concept transformable_ranges =
0523             viewable_range<Rng1> && input_range<Rng1> &&
0524             viewable_range<Rng2> && input_range<Rng2> &&
0525             copy_constructible<Fun> &&
0526             CPP_concept_ref(views::transformable_ranges_, Rng1, Rng2, Fun);
0527         // clang-format on
0528 
0529         struct transform_base_fn
0530         {
0531             template(typename Rng, typename Fun)(
0532                 requires transformable_range<Rng, Fun>)
0533             constexpr transform_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun)
0534                 const
0535             {
0536                 return {all(static_cast<Rng &&>(rng)), std::move(fun)};
0537             }
0538 
0539             template(typename Rng1, typename Rng2, typename Fun)(
0540                 requires transformable_ranges<Rng1, Rng2, Fun>)
0541             constexpr transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
0542             operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
0543             {
0544                 return {all(static_cast<Rng1 &&>(rng1)),
0545                         all(static_cast<Rng2 &&>(rng2)),
0546                         std::move(fun)};
0547             }
0548         };
0549 
0550         /// # ranges::views::transform
0551         /// The transform view takes in a function `T -> U` and converts an input
0552         /// range of `T` into an output range of `U` by calling the function on every
0553         /// element of the input range.
0554         ///
0555         /// ## Example
0556         /// \snippet example/view/transform.cpp transform example
0557         ///
0558         /// ### Output
0559         /// \include example/view/transform_golden.txt
0560         ///
0561         /// ## Syntax
0562         /// ```cpp
0563         /// auto output_range = input_range | ranges::views::transform(transform_func);
0564         /// ```
0565         ///
0566         /// ## Parameters
0567         /// <pre><b>transform_func</b></pre>
0568         ///   - Maps an input value to an output value (`transform_func(T) -> U`)
0569         ///
0570         /// <pre><b>input_range</b></pre>
0571         ///   - The range of elements to transform
0572         ///   - Reference type: `T`
0573         ///
0574         /// <pre><b>output_range</b></pre>
0575         ///   - The range of output values
0576         ///   - Reference type: `U`
0577         ///   - Value type: `decay_t<U>`
0578         ///   - This range will have the same category as the input range (excluding
0579         ///   contiguous ranges). Contiguous ranges are reduced to random access ranges.
0580         ///
0581         struct transform_fn : transform_base_fn
0582         {
0583             using transform_base_fn::operator();
0584 
0585             template<typename Fun>
0586             constexpr auto operator()(Fun fun) const
0587             {
0588                 return make_view_closure(bind_back(transform_base_fn{}, std::move(fun)));
0589             }
0590         };
0591 
0592         /// \relates transform_fn
0593         /// \ingroup group-views
0594         RANGES_INLINE_VARIABLE(transform_fn, transform)
0595     } // namespace views
0596 
0597     namespace cpp20
0598     {
0599         namespace views
0600         {
0601             using ranges::views::transform;
0602         }
0603         template(typename Rng, typename F)(
0604             requires input_range<Rng> AND copy_constructible<F> AND view_<Rng> AND
0605                 std::is_object<F>::value AND
0606                     regular_invocable<F &, iter_reference_t<iterator_t<Rng>>>)
0607             using transform_view = ranges::transform_view<Rng, F>;
0608     } // namespace cpp20
0609     /// @}
0610 } // namespace ranges
0611 
0612 #include <range/v3/detail/epilogue.hpp>
0613 
0614 #include <range/v3/detail/satisfy_boost_range.hpp>
0615 RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view)
0616 RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view)
0617 
0618 #endif