I really like to use cmcstl2, an implementation of the Ranges TS. I especially like the optional projections on every STL-algorithm. Invocable
types get forwarded (ehm... or not) like this: (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));
}
As reference: The range-v3 library implements it like this: (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 try to understand the difference and reasoning of both approaches.
Why should I take Invocable
types by value anyway?
Why should I not use perfect forwarding for these types?
I understand the second approach more than I do for the first one, since I understand the methodology of taking sink arguments by value.