#ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP #define SPROUT_FUNCTIONAL_BIND_BIND_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { // 20.8.9 bind // // is_bind_expression // 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 {}; 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_pack::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_pack::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_pack::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()(sprout::tuples::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() ); } }; // // is_bind_expression // 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) { return sprout::bind(sprout::forward(f), sprout::forward(args)...); } template inline SPROUT_CONSTEXPR typename sprout::detail::bindres_helper::type const cbind(F&& f, BoundArgs&&... args) { return sprout::bind(sprout::forward(f), sprout::forward(args)...); } } // namespace sprout #endif // #ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP