#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 #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, 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 SPROUT_CONSTEXPR 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)); } template struct is_variadic_bounds : public std::false_type {}; template struct is_variadic_bounds< Bounds, typename std::enable_if::value>::type > : public std::integral_constant< bool, (sprout::is_placeholder::value - 1, Bounds>::type>::value <= sprout::is_placeholder::value ) > {}; template struct tail_bounds_place : public std::integral_constant {}; template struct tail_bounds_place< Bounds, typename std::enable_if::value>::type > : public std::integral_constant< int, (sprout::is_placeholder::value - sprout::is_placeholder::value - 1, Bounds>::type>::value ) > {}; template struct bounds_size : public std::integral_constant< std::size_t, sprout::detail::is_variadic_bounds::value ? (sprout::tuples::tuple_size::value - 1) + (sizeof...(Args) - sprout::detail::tail_bounds_place::value) : sprout::tuples::tuple_size::value > {}; template struct bound_indexes : public sprout::make_index_tuple::value> {}; template struct is_variadic_part : public std::integral_constant< bool, sprout::detail::is_variadic_bounds::value && (I >= sprout::tuples::tuple_size::value) > {}; template struct bound_element : public sprout::tuples::tuple_element {}; template struct bound_element< I, Bounds, typename std::enable_if::value>::type > { public: typedef sprout::placeholder::value + sprout::detail::tail_bounds_place::value + 1> type; }; template struct complete_bounds_impl; template struct complete_bounds_impl > { public: typedef sprout::tuples::tuple...> type; }; template struct complete_bounds : public sprout::detail::complete_bounds_impl::type> {}; struct get_bound_helper { public: template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && !std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds& bound_args) -> decltype(sprout::tuples::get(bound_args)) { return sprout::tuples::get(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && !std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds const& bound_args) -> decltype(sprout::tuples::get(bound_args)) { return sprout::tuples::get(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds volatile& bound_args) -> decltype(sprout::detail::volget(bound_args)) { return sprout::detail::volget(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds const volatile& bound_args) -> decltype(sprout::detail::volget(bound_args)) { return sprout::detail::volget(bound_args); } }; template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::type>::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR typename sprout::detail::bound_element::type>::type get_bound(Bounds&&) { typedef typename sprout::detail::bound_element::type>::type type; return type(); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::type>::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR auto get_bound(Bounds&& bound_args) -> decltype(sprout::detail::get_bound_helper::get_bound(std::forward(bound_args))) { return sprout::detail::get_bound_helper::get_bound(std::forward(bound_args)); } } // namespace detail // // binder // template class binder; template class binder : public sprout::weak_result_type { private: typedef binder self_type; typedef sprout::tuples::tuple bounds_type; private: Functor f_; bounds_type bound_args_; private: template Result call(sprout::tuples::tuple&& args, sprout::index_tuple) { return f_( sprout::detail::mu::type>() (sprout::detail::get_bound(bound_args_), args)... ); } template SPROUT_CONSTEXPR Result call_c(sprout::tuples::tuple&& args, sprout::index_tuple) const { return f_( sprout::detail::mu::type const>() (sprout::detail::get_bound(bound_args_), args)... ); } template Result call_v(sprout::tuples::tuple&& args, sprout::index_tuple) volatile { return f_( sprout::detail::mu::type volatile>() (sprout::detail::get_bound(bound_args_), args)... ); } template SPROUT_CONSTEXPR Result call_cv(sprout::tuples::tuple&& args, sprout::index_tuple) const volatile { return f_( sprout::detail::mu::type const volatile>() (sprout::detail::get_bound(bound_args_), args)... ); } private: template< typename... Args, sprout::index_t... Indexes > static SPROUT_CONSTEXPR decltype( std::declval()( sprout::detail::mu::type>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static SPROUT_CONSTEXPR decltype( std::declval= 0), typename std::add_const::type>::type&>()( sprout::detail::mu::type const>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_c_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static SPROUT_CONSTEXPR decltype( std::declval= 0), typename std::add_volatile::type>::type&>()( sprout::detail::mu::type volatile>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_v_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static SPROUT_CONSTEXPR decltype( std::declval= 0), typename std::add_cv::type>::type&>()( sprout::detail::mu::type const volatile>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_cv_(sprout::tuples::tuple&& args, sprout::index_tuple); 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( call_(std::declval >(), sprout::detail::bound_indexes::make()) ) > Result operator()(Args&&... args) { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( call_c_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const { return call_c( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( call_v_(std::declval >(), sprout::detail::bound_indexes::make()) ) > Result operator()(Args&&... args) volatile { return call_v( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( call_cv_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const volatile { return call_cv( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; // // res_binder // template class res_binder; template class res_binder { private: typedef res_binder self_type; typedef sprout::tuples::tuple bounds_type; 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::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) { f_(sprout::detail::mu()(sprout::detail::get_bound(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::detail::get_bound(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::detail::get_bound(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::get_bound(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::get_bound(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::get_bound(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::get_bound(bound_args_), args)...); } public: typedef Result result_type; template explicit res_binder(Functor const& f, Args&&... args) : f_(f) , bound_args_(sprout::forward(args)...) {} res_binder(res_binder const&) = default; template result_type operator()(Args&&... args) { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template result_type operator()(Args&&... args) volatile { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const volatile { return call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; // // 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 complete_placeholder; template struct complete_placeholder< Index, BoundArg, typename std::enable_if::value == sprout::is_placeholder::value)>::type > { public: typedef BoundArg type; }; template struct complete_placeholder< Index, BoundArg, typename std::enable_if<(sprout::is_placeholder::value == sprout::is_placeholder::value)>::type > { public: typedef sprout::placeholder type; }; template struct binder_complete_placeholders_impl; template struct binder_complete_placeholders_impl, BoundArgs...> { public: typedef sprout::binder::type...)> type; }; template struct binder_complete_placeholders : public sprout::detail::binder_complete_placeholders_impl::type, BoundArgs...> {}; template struct res_binder_complete_placeholders_impl; template struct res_binder_complete_placeholders_impl, BoundArgs...> { public: typedef sprout::res_binder::type...)> type; }; template struct res_binder_complete_placeholders : public sprout::detail::res_binder_complete_placeholders_impl::type, BoundArgs...> {}; template struct bind_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type func_type; typedef typename sprout::detail::binder_complete_placeholders::type...>::type type; }; template struct res_bind_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type functor_type; typedef typename sprout::detail::res_binder_complete_placeholders::type...>::type type; }; } // namespace detail // // bind_result // res_bind_result // template struct bind_result { public: typedef typename sprout::detail::bind_helper::type type; }; template struct res_bind_result { public: typedef typename sprout::detail::res_bind_helper::type type; }; // // bind // template inline SPROUT_CONSTEXPR typename sprout::bind_result::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::res_bind_result::type bind(F&& f, BoundArgs&&... args) { typedef sprout::detail::res_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)...); } // // 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::res_bind_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