#ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP #define SPROUT_FUNCTIONAL_BIND_BIND_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { // 20.8.9 bind template struct is_bind_expression : public std::false_type {}; template struct is_bind_expression : public sprout::is_bind_expression {}; template struct is_bind_expression : public sprout::is_bind_expression {}; template struct is_bind_expression : public sprout::is_bind_expression {}; template struct is_placeholder : public std::integral_constant {}; template struct is_placeholder : public sprout::is_placeholder {}; template struct is_placeholder : public sprout::is_placeholder {}; template struct is_placeholder : public sprout::is_placeholder {}; // // placeholder // template struct placeholder {}; namespace placeholders { namespace { SPROUT_STATIC_CONSTEXPR sprout::placeholder<1> _1{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<2> _2{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<3> _3{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<4> _4{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<5> _5{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<6> _6{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<7> _7{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<8> _8{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<9> _9{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<10> _10{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<11> _11{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<12> _12{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<13> _13{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<14> _14{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<15> _15{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<16> _16{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<17> _17{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<18> _18{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<19> _19{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<20> _20{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<21> _21{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<22> _22{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<23> _23{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<24> _24{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<25> _25{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<26> _26{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<27> _27{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<28> _28{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<29> _29{}; SPROUT_STATIC_CONSTEXPR sprout::placeholder<30> _30{}; } // anonymous-namespace } // namespace placeholders using sprout::placeholders::_1; using sprout::placeholders::_2; using sprout::placeholders::_3; using sprout::placeholders::_4; using sprout::placeholders::_5; using sprout::placeholders::_6; using sprout::placeholders::_7; using sprout::placeholders::_8; using sprout::placeholders::_9; using sprout::placeholders::_10; using sprout::placeholders::_11; using sprout::placeholders::_12; using sprout::placeholders::_13; using sprout::placeholders::_14; using sprout::placeholders::_15; using sprout::placeholders::_16; using sprout::placeholders::_17; using sprout::placeholders::_18; using sprout::placeholders::_19; using sprout::placeholders::_20; using sprout::placeholders::_21; using sprout::placeholders::_2; using sprout::placeholders::_23; using sprout::placeholders::_24; using sprout::placeholders::_25; using sprout::placeholders::_26; using sprout::placeholders::_27; using sprout::placeholders::_28; using sprout::placeholders::_29; using sprout::placeholders::_30; template struct is_placeholder > : public std::integral_constant {}; namespace detail { struct no_tuple_element; template struct safe_tuple_element_impl : tuple_element {}; template struct safe_tuple_element_impl { public: typedef sprout::detail::no_tuple_element type; }; template struct safe_tuple_element : public sprout::detail::safe_tuple_element_impl::value)> {}; template< typename Arg, bool IsBindExp = sprout::is_bind_expression::value, bool IsPlaceholder = (sprout::is_placeholder::value > 0) > class mu; template class mu, false, false> { public: typedef T& result_type; public: template SPROUT_CONSTEXPR result_type operator()(CVRef& arg, Tuple&) const volatile { // ??? //return arg.get(); return const_cast::type>::type&>(arg).get(); } }; template class mu { private: template SPROUT_CONSTEXPR auto call( CVArg& arg, sprout::tuples::tuple& tuple, sprout::index_tuple ) const volatile -> decltype(arg(std::declval()...)) { return arg(sprout::forward(sprout::tuples::get(tuple))...); } public: template SPROUT_CONSTEXPR auto operator()(CVArg& arg, sprout::tuples::tuple& tuple) const volatile -> decltype(arg(std::declval()...)) { return call(arg, tuple, sprout::index_range<0, sizeof...(Args)>::make()); } }; template class mu { public: template class result; template class result { private: typedef typename sprout::detail::safe_tuple_element< (sprout::is_placeholder::value - 1), Tuple >::type base_type; public: typedef typename std::add_rvalue_reference::type type; }; public: template typename result::type SPROUT_CONSTEXPR operator()(Arg const volatile&, Tuple& tuple) const volatile { return sprout::forward::type>( sprout::tuples::get<(sprout::is_placeholder::value - 1)>(tuple) ); } }; template class mu { public: template struct result; template struct result { public: typedef typename std::add_lvalue_reference::type type; }; public: template SPROUT_CONSTEXPR CVArg&& operator()(CVArg&& arg, Tuple&) const volatile { return sprout::forward(arg); } }; template struct maybe_wrap_member_pointer { public: typedef T type; public: static SPROUT_CONSTEXPR T const& do_wrap(T const& x) { return x; } static SPROUT_CONSTEXPR T&& do_wrap(T&& x) { return static_cast(x); } }; template struct maybe_wrap_member_pointer { public: typedef sprout::mem_fn_adaptor type; public: static SPROUT_CONSTEXPR type do_wrap(T Class::* pm) { return type(pm); } }; template<> struct maybe_wrap_member_pointer { public: typedef void type; }; template inline auto volget(sprout::tuples::tuple volatile& tuple) -> typename sprout::tuples::tuple_element >::type volatile& { return sprout::tuples::get(const_cast&>(tuple)); } template inline SPROUT_CONSTEXPR auto volget(sprout::tuples::tuple const volatile& tuple) -> typename sprout::tuples::tuple_element >::type const volatile& { return sprout::tuples::get(const_cast const&>(tuple)); } } // namespace detail // // binder // template class binder; template class binder : public sprout::weak_result_type { private: typedef binder self_type; typedef typename sprout::index_range<0, sizeof...(BoundArgs)>::type bound_indexes; private: Functor f_; sprout::tuples::tuple bound_args_; private: template Result call(sprout::tuples::tuple&& args, sprout::index_tuple) { return f_(sprout::detail::mu()(sprout::tuples::get(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call_c(sprout::tuples::tuple&& args, sprout::index_tuple) const { return f_(sprout::detail::mu()(sprout::tuples::get(bound_args_), args)...); } template Result call_v(sprout::tuples::tuple&& args, sprout::index_tuple) volatile { return f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call_cv(sprout::tuples::tuple&& args, sprout::index_tuple) const volatile { return f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } public: template explicit SPROUT_CONSTEXPR binder(Functor const& f, Args&&... args) : f_(f) , bound_args_(sprout::forward(args)...) {} binder(binder const&) = default; template< typename... Args, typename Result = decltype( std::declval()( sprout::detail::mu()( std::declval(), std::declval&>() )... ) ) > Result operator()(Args&&... args) { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template< typename... Args, typename Result = decltype( std::declval= 0), typename std::add_const::type>::type>()( sprout::detail::mu()( std::declval(), std::declval&>() )... ) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const { return call_c( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template< typename... Args, typename Result = decltype( std::declval= 0), typename std::add_volatile::type>::type>()( sprout::detail::mu()( std::declval(), std::declval&>() )... ) ) > Result operator()(Args&&... args) volatile { return call_v( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template< typename... Args, typename Result = decltype( std::declval= 0), typename std::add_cv::type>::type>()( sprout::detail::mu()( std::declval(), std::declval&>() )... ) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const volatile { return call_cv( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } }; // // bind_result // template class bind_result; template class bind_result { private: typedef bind_result self_type; typedef typename sprout::index_range<0, sizeof...(BoundArgs)>::type bound_indexes; private: template struct enable_if_void : public std::enable_if::value, int> {}; template struct disable_if_void : public std::enable_if::value, int> {}; private: Functor f_; sprout::tuples::tuple bound_args_; private: template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) { return f_(sprout::detail::mu()(sprout::tuples::get(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) { f_(sprout::detail::mu()(get(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) const { return f_(sprout::detail::mu()(sprout::tuples::get(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) const { f_(sprout::detail::mu()(sprout::tuples::get(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) volatile { return f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) volatile { f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) const volatile { return f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) const volatile { f_(sprout::detail::mu()(sprout::detail::volget(bound_args_), args)...); } public: typedef Result result_type; template explicit bind_result(Functor const& f, Args&&... args) : f_(f) , bound_args_(sprout::forward(args)...) {} bind_result(bind_result const&) = default; template result_type operator()(Args&&... args) { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template result_type operator()(Args&&... args) volatile { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const volatile { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), bound_indexes() ); } }; template struct is_bind_expression > : public std::true_type {}; template struct is_bind_expression > : public std::true_type {}; namespace detail { template struct bind_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type func_type; typedef sprout::binder::type...)> type; }; template struct bindres_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type functor_type; typedef sprout::bind_result::type...)> type; }; } // namespace detail // // bind // template inline SPROUT_CONSTEXPR typename sprout::detail::bind_helper::type bind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } template inline SPROUT_CONSTEXPR typename sprout::detail::bindres_helper::type bind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bindres_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } // // cbind // template inline SPROUT_CONSTEXPR typename sprout::detail::bind_helper::type const cbind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } template inline SPROUT_CONSTEXPR typename sprout::detail::bindres_helper::type const cbind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bindres_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } } // namespace sprout #endif // #ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP