I really like to use cmcstl2 , an implementation of TS ranges. I especially like the optional projections on each STL algorithm. Invocable
types are passed (ehm ... or not) as follows: ( min_element.hpp )
template <ForwardIterator I, Sentinel<I> S, class Comp = less<>, class Proj = identity> requires IndirectStrictWeakOrder< Comp, projected<I, Proj>>() I min_element(I first, S last, Comp comp = Comp{}, Proj proj = Proj{}); template <ForwardRange Rng, class Comp = less<>, class Proj = identity> requires IndirectStrictWeakOrder< Comp, projected<iterator_t<Rng>, Proj>>() safe_iterator_t<Rng> min_element(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{}) { return __stl2::min_element(__stl2::begin(rng), __stl2::end(rng), __stl2::ref(comp), __stl2::ref(proj)); }
By reference: the range-v3 library implements it as follows: ( min_element.hpp )
struct min_element_fn { template<typename I, typename S, typename C = ordered_less, typename P = ident, CONCEPT_REQUIRES_(ForwardIterator<I>() && Sentinel<S, I>() && IndirectRelation<C, projected<I, P>>())> I operator()(I begin, S end, C pred = C{}, P proj = P{}) const; template<typename Rng, typename C = ordered_less, typename P = ident, typename I = range_iterator_t<Rng>, CONCEPT_REQUIRES_(ForwardRange<Rng>() && IndirectRelation<C, projected<I, P>>())> range_safe_iterator_t<Rng> operator()(Rng &&rng, C pred = C{}, P proj = P{}) const { return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj)); } };
Now I am trying to understand the difference and reasoning of both approaches. Why should I accept Invocable
types by value anyway? Why shouldn't I use perfect forwarding for these types?
I understand the second approach more than the first, as I understand the methodology for accepting immersion arguments at a cost.