Using the range-v3 library (by @EricNiebler) makes the algorithmic writing code much more compact, for example. here's how to create a bunch of random numbers:
#include <range/v3/all.hpp> #include <iostream> #include <vector> int main() { using namespace ranges; auto const N = 10; std::vector<int> v; v.reserve(N); v |= action::push_back(view::iota(0, N)); random_shuffle(v); copy(v, ostream_iterator<>(std::cout, ",")); }
Living example.
However, I would prefer to extend the pipeline with a hypothetical action::random_shuffle() as follows
v |= action::push_back(view::iota(0, N)) | action::random_shuffle();
Here is my attempt to write such an action (unfortunately, writing the new range-v3 code is a bit more complicated than using the library)
#include <functional> // bind, placeholders::_1 namespace ranges { inline namespace v3 { /// \addtogroup group-actions /// @{ namespace action { struct random_shuffle_fn { private: friend action_access; static auto bind(random_shuffle_fn random_shuffle) RANGES_DECLTYPE_AUTO_RETURN ( std::bind(random_shuffle, std::placeholders::_1) ) template<typename Gen> static auto bind(random_shuffle_fn random_shuffle, Gen && rand) RANGES_DECLTYPE_AUTO_RETURN ( std::bind(random_shuffle, std::placeholders::_1, bind_forward<Gen>(rand)) ) public: struct ConceptImpl { template<typename Rng, typename I = range_iterator_t<Rng>> auto requires_(Rng&&) -> decltype( concepts::valid_expr( concepts::model_of<concepts::RandomAccessRange, Rng>(), concepts::is_true(Permutable<I>()) )); }; template<typename Rng> using Concept = concepts::models<ConceptImpl, Rng>; template<typename Rng, CONCEPT_REQUIRES_(Concept<Rng>())> Rng operator()(Rng && rng) const { ranges::random_shuffle(rng); return std::forward<Rng>(rng); } template<typename Rng, typename Gen, CONCEPT_REQUIRES_(Concept<Rng>())> Rng operator()(Rng && rng, Gen && rand) const { ranges::random_shuffle(rng, std::forward<Gen>(rand)); return std::forward<Rng>(rng); } #ifndef RANGES_DOXYGEN_INVOKED template<typename Rng> void operator()(Rng &&) const { CONCEPT_ASSERT_MSG(RandomAccessRange<Rng>(), "The object on which action::random_shuffle operates must be a model of the " "RandomAccessRange concept."); using I = range_iterator_t<Rng>; CONCEPT_ASSERT_MSG(Permutable<I>(), "The iterator type of the range passed to action::random_shuffle must allow its " "elements to be permuted; that is, the values must be movable and the " "iterator must be mutable."); } #endif }; /// \ingroup group-actions /// \relates sort_fn /// \sa `action` namespace { constexpr auto&& random_shuffle = static_const<action<random_shuffle_fn>>::value; } } /// @} } }
A living example that cannot be compiled because some operator() deeply hidden is not found somewhere.
As far as I can see, I correctly passed the above code from a similar code, for example. action::sort() . The only difference is that random_shuffle() has two overloads (one accepts a random generator), while all other actions (including sort ) have one overload with default values ββfor their additional parameters (comparators, predicates, projectors, etc. ..). This means two static bind() functions from random_shuffle_fn above, while all other actions have only one bind() overload.
Question : how to write a range-v3 action for random_shuffle?