使用
range-v3 library(由@EricNiebler),使得编写算法代码更加紧凑,例如这是如何生成一堆随机数:
#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,",")); }
但是,我更愿意使用假设的动作:: random_shuffle()来扩展管道
v |= action::push_back(view::iota(0,N)) | action::random_shuffle();
这是我尝试编写这样的动作(不幸的是,编写新的range-v3代码比使用库更加冗长)
#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; } } /// @} } }
Live Example无法编译,因为某些operator()深藏在某处未找到.
据我所见,我忠实地从类似的代码中转换了上述代码,例如action :: sort().唯一的区别是random_shuffle()有两个重载(一个采用随机生成器),而所有其他动作(包括sort)都有一个重载,其额外参数的默认值(比较器,谓词,投影仪等) .这转换为上面的random_shuffle_fn的两个bind()静态成员函数,而所有其他操作只有一个bind()重载.
问题:如何为random_shuffle编写range-v3动作?
解决方法
你有两个不明确的random_shuffle_function :: operator()(Rng&&)重载,你的“错误捕获”重载需要被限制为只接受那些正确的重载拒绝的参数(我们真的需要C Concepts所以我再也没有了到SFINAE约束重载):
#ifndef RANGES_DOXYGEN_INVOKED template<typename Rng,CONCEPT_REQUIRES_(!Concept<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
此外,您需要管道操作:: random_shuffle:
v |= action::push_back(view::iota(0,N)) | action::random_shuffle;