// Boost.TypeErasure library // // Copyright 2011 Steven Watanabe // // Distributed under the Boost Software License Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // $Id$ #if !defined(BOOST_PP_IS_ITERATING) #ifndef BOOST_TYPE_ERASURE_CALL_HPP_INCLUDED #define BOOST_TYPE_ERASURE_CALL_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace type_erasure { #ifndef BOOST_TYPE_ERASURE_DOXYGEN template class any; template class binding; #endif namespace detail { template struct is_placeholder_arg : ::boost::type_erasure::is_placeholder< typename ::boost::remove_cv< typename ::boost::remove_reference::type >::type > {}; template int maybe_get_table(const T& arg, const Table*& table, boost::mpl::true_) { if(table == 0) { table = &::boost::type_erasure::detail::access::table(arg); } return 0; } template int maybe_get_table(const T&, const Table*&, boost::mpl::false_) { return 0; } template ::boost::type_erasure::detail::storage& convert_arg(any_base& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(any_base >& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(const any_base& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage& convert_arg(const any_base >& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(const any_base >& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage& convert_arg(param& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(param& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(const param& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template const ::boost::type_erasure::detail::storage& convert_arg(any_base >&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage& convert_arg(any_base >&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage&& convert_arg(any_base >&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(std::move(arg)); } template ::boost::type_erasure::detail::storage&& convert_arg(any_base >& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage&& convert_arg(const any_base >& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template const ::boost::type_erasure::detail::storage& convert_arg(param&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage& convert_arg(param&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage&& convert_arg(param&& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(std::move(arg)); } template ::boost::type_erasure::detail::storage&& convert_arg(param& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template ::boost::type_erasure::detail::storage&& convert_arg(const param& arg, boost::mpl::true_) { return ::boost::type_erasure::detail::access::data(arg); } template T&& convert_arg(T&& arg, boost::mpl::false_) { return std::forward(arg); } #else template T& convert_arg(T& arg, boost::mpl::false_) { return arg; } #endif } #ifdef BOOST_TYPE_ERASURE_DOXYGEN /** * Dispatches a type erased function. * * @c Op must be a primitive concept which is present in * @c Concept. Its signature determines how the arguments of * \call are handled. If the argument is a @ref placeholder, * \call expects an @ref any using that @ref placeholder. * This @ref any is unwrapped by \call. The type that * it stores must be the same type specified by @c binding. * Any arguments that are not placeholders in the signature * of @c Op are passed through unchanged. * * If @c binding is not specified, it will be deduced from * the arguments. Naturally this requires at least one * argument to be an @ref any. In this case, all @ref any * arguments must have the same @ref binding. * * \return The result of the operation. If the result type * of the signature of @c Op is a placeholder, the * result will be converted to the appropriate @ref * any type. * * \throws bad_function_call if @ref relaxed is * in @c Concept and there is a type mismatch. * * Example: * * @code * typedef mpl::vector< * copy_constructible<_b>, * addable<_a, int, _b> > concept; * any a = ...; * any b(call(addable<_a, int, _b>(), a, 10)); * @endcode * * The signature of @ref addable is _b(const _a&, const int&) */ template typename ::boost::type_erasure::detail::call_impl::type call(const binding& binding_arg, const Op&, U&&... args); /** * \overload */ template typename ::boost::type_erasure::detail::call_impl::type call(const Op&, U&&... args); #else namespace detail { template::type::value> struct call_impl {}; template struct call_result : call_impl< typename ::boost::type_erasure::detail::get_signature::type, Args, Concept> {}; template struct call_result< ::boost::type_erasure::binding, Args, Concept > {}; } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) namespace detail { template void ignore(const T&...) {} #ifndef BOOST_TYPE_ERASURE_USE_MP11 template const ::boost::type_erasure::binding< typename ::boost::type_erasure::detail::extract_concept::type>* extract_table(R(*)(T...), const U&... arg) { const ::boost::type_erasure::binding< typename ::boost::type_erasure::detail::extract_concept< void(T...), U...>::type>* result = 0; // the order that we run maybe_get_table in doesn't matter ignore(::boost::type_erasure::detail::maybe_get_table( arg, result, ::boost::type_erasure::detail::is_placeholder_arg())...); BOOST_ASSERT(result != 0); return result; } #else template const ::boost::type_erasure::binding< ::boost::type_erasure::detail::extract_concept_t< ::boost::mp11::mp_list, ::boost::mp11::mp_list > >* extract_table(R(*)(T...), const U&... arg) { const ::boost::type_erasure::binding< ::boost::type_erasure::detail::extract_concept_t< ::boost::mp11::mp_list, ::boost::mp11::mp_list > >* result = 0; // the order that we run maybe_get_table in doesn't matter ignore(::boost::type_erasure::detail::maybe_get_table( arg, result, ::boost::type_erasure::detail::is_placeholder_arg())...); BOOST_ASSERT(result != 0); return result; } #endif template struct call_impl_dispatch; template struct call_impl_dispatch { typedef R type; template static R apply(const ::boost::type_erasure::binding* table, U... arg) { return table->template find()( ::boost::type_erasure::detail::convert_arg( ::std::forward(arg), ::boost::type_erasure::detail::is_placeholder_arg())...); } }; template struct call_impl_dispatch { typedef ::boost::type_erasure::any type; template static type apply(const ::boost::type_erasure::binding* table, U... arg) { return type(table->template find()( ::boost::type_erasure::detail::convert_arg( ::std::forward(arg), ::boost::type_erasure::detail::is_placeholder_arg())...), *table); } }; template struct call_impl : ::boost::type_erasure::detail::call_impl_dispatch< R(T...), void(U...), Concept, ::boost::type_erasure::detail::is_placeholder_arg::value > { }; #ifndef BOOST_TYPE_ERASURE_USE_MP11 template struct call_impl : ::boost::type_erasure::detail::call_impl_dispatch< R(T...), void(U...), typename ::boost::type_erasure::detail::extract_concept< void(T...), typename ::boost::remove_reference::type... >::type, ::boost::type_erasure::detail::is_placeholder_arg::value > { }; #else template struct call_impl : ::boost::type_erasure::detail::call_impl_dispatch< R(T...), void(U...), ::boost::type_erasure::detail::extract_concept_t< ::boost::mp11::mp_list, ::boost::mp11::mp_list< ::boost::remove_reference_t...> >, ::boost::type_erasure::detail::is_placeholder_arg::value > { }; #endif } template< class Concept, class Op, class... U > typename ::boost::type_erasure::detail::call_result< Op, void(U&&...), Concept >::type unchecked_call( const ::boost::type_erasure::binding& table, const Op&, U&&... arg) { return ::boost::type_erasure::detail::call_impl< typename ::boost::type_erasure::detail::get_signature::type, void(U&&...), Concept >::template apply< typename ::boost::type_erasure::detail::adapt_to_vtable::type >(&table, std::forward(arg)...); } template typename ::boost::type_erasure::detail::call_result< Op, void(U&&...), Concept >::type call( const ::boost::type_erasure::binding& table, const Op& f, U&&... arg) { ::boost::type_erasure::require_match(table, f, std::forward(arg)...); return ::boost::type_erasure::unchecked_call(table, f, std::forward(arg)...); } template typename ::boost::type_erasure::detail::call_result< Op, void(U&&...) >::type unchecked_call( const Op&, U&&... arg) { return ::boost::type_erasure::detail::call_impl< typename ::boost::type_erasure::detail::get_signature::type, void(U&&...) >::template apply< typename ::boost::type_erasure::detail::adapt_to_vtable::type >(::boost::type_erasure::detail::extract_table( static_cast::type*>(0), arg...), std::forward(arg)...); } template typename ::boost::type_erasure::detail::call_result< Op, void(U&&...) >::type call( const Op& f, U&&... arg) { ::boost::type_erasure::require_match(f, std::forward(arg)...); return ::boost::type_erasure::unchecked_call(f, std::forward(arg)...); } #else #define BOOST_PP_FILENAME_1 #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY) #include BOOST_PP_ITERATE() #endif #endif } } #endif #else #define N BOOST_PP_ITERATION() #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_TYPE_ERASURE_CONVERT_ARG(z, n, data) \ ::boost::type_erasure::detail::convert_arg( \ std::forward(BOOST_PP_CAT(arg, n)), \ ::boost::type_erasure::detail::is_placeholder_arg()) #else #define BOOST_TYPE_ERASURE_CONVERT_ARG(z, n, data) \ ::boost::type_erasure::detail::convert_arg( \ BOOST_PP_CAT(arg, n), \ ::boost::type_erasure::detail::is_placeholder_arg()) #endif #define BOOST_TYPE_ERASURE_GET_TABLE(z, n, data) \ ::boost::type_erasure::detail::maybe_get_table( \ BOOST_PP_CAT(arg, n), \ result, \ ::boost::type_erasure::detail::is_placeholder_arg()); namespace detail { #if N != 0 template< class R, BOOST_PP_ENUM_PARAMS(N, class T), BOOST_PP_ENUM_PARAMS(N, class U)> const ::boost::type_erasure::binding< typename ::boost::type_erasure::detail::BOOST_PP_CAT(extract_concept, N)< BOOST_PP_ENUM_PARAMS(N, T), BOOST_PP_ENUM_PARAMS(N, U)>::type>* BOOST_PP_CAT(extract_table, N)(R(*)(BOOST_PP_ENUM_PARAMS(N, T)), BOOST_PP_ENUM_BINARY_PARAMS(N, const U, &arg)) { const ::boost::type_erasure::binding< typename ::boost::type_erasure::detail::BOOST_PP_CAT(extract_concept, N)< BOOST_PP_ENUM_PARAMS(N, T), BOOST_PP_ENUM_PARAMS(N, U)>::type>* result = 0; BOOST_PP_REPEAT(N, BOOST_TYPE_ERASURE_GET_TABLE, ~) BOOST_ASSERT(result != 0); return result; } #endif template< class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T) BOOST_PP_ENUM_TRAILING_PARAMS(N, class U), class Concept #if N != 0 = typename ::boost::type_erasure::detail::BOOST_PP_CAT(extract_concept, N)< BOOST_PP_ENUM_PARAMS(N, T), BOOST_PP_ENUM_PARAMS(N, U) >::type #endif , bool ReturnsAny = ::boost::type_erasure::detail::is_placeholder_arg::value> struct BOOST_PP_CAT(call_impl, N); template< class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T) BOOST_PP_ENUM_TRAILING_PARAMS(N, class U), class Concept > struct BOOST_PP_CAT(call_impl, N)< R BOOST_PP_ENUM_TRAILING_PARAMS(N, T) BOOST_PP_ENUM_TRAILING_PARAMS(N, U), Concept, false > { typedef R type; template static R apply(const ::boost::type_erasure::binding* table BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, arg)) { return table->template find()( BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_CONVERT_ARG, ~)); } }; template< class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T) BOOST_PP_ENUM_TRAILING_PARAMS(N, class U), class Concept > struct BOOST_PP_CAT(call_impl, N)< R BOOST_PP_ENUM_TRAILING_PARAMS(N, T) BOOST_PP_ENUM_TRAILING_PARAMS(N, U), Concept, true > { typedef ::boost::type_erasure::any type; template static type apply(const ::boost::type_erasure::binding* table BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, arg)) { return type(table->template find()( BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_CONVERT_ARG, ~)), *table); } }; template< class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T) BOOST_PP_ENUM_TRAILING_PARAMS(N, class U), class Concept > struct call_impl : BOOST_PP_CAT(call_impl, N) {}; #if N != 0 template< class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T) BOOST_PP_ENUM_TRAILING_PARAMS(N, class U) > struct call_impl : BOOST_PP_CAT(call_impl, N) {}; #endif } #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES #define RREF & #define BOOST_TYPE_ERASURE_FORWARD_ARGS(N, X, x) BOOST_PP_ENUM_TRAILING_PARAMS(N, x) #else #define RREF && #define BOOST_TYPE_ERASURE_FORWARD_ARGS_I(z, n, data) std::forward(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n)) #define BOOST_TYPE_ERASURE_FORWARD_ARGS(N, X, x) BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_ARGS_I, (X, x)) #endif template< class Concept, class Op BOOST_PP_ENUM_TRAILING_PARAMS(N, class U) > typename ::boost::type_erasure::detail::call_result< Op, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)), Concept >::type unchecked_call( const ::boost::type_erasure::binding& table, const Op& BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg)) { return ::boost::type_erasure::detail::call_impl< typename ::boost::type_erasure::detail::get_signature::type, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)), Concept >::template apply< typename ::boost::type_erasure::detail::adapt_to_vtable::type >(&table BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg)); } template< class Concept, class Op BOOST_PP_ENUM_TRAILING_PARAMS(N, class U) > typename ::boost::type_erasure::detail::call_result< Op, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)), Concept >::type call( const ::boost::type_erasure::binding& table, const Op& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg)) { ::boost::type_erasure::require_match(table, f BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg)); return ::boost::type_erasure::unchecked_call(table, f BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg)); } #if N != 0 template< class Op BOOST_PP_ENUM_TRAILING_PARAMS(N, class U) > typename ::boost::type_erasure::detail::call_result< Op, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)) >::type unchecked_call( const Op& BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg)) { return ::boost::type_erasure::detail::call_impl< typename ::boost::type_erasure::detail::get_signature::type, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)) >::template apply< typename ::boost::type_erasure::detail::adapt_to_vtable::type >( ::boost::type_erasure::detail::BOOST_PP_CAT(extract_table, N)( (typename ::boost::type_erasure::detail::get_signature::type*)0, BOOST_PP_ENUM_PARAMS(N, arg)) BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg) ); } template< class Op BOOST_PP_ENUM_TRAILING_PARAMS(N, class U) > typename ::boost::type_erasure::detail::call_result< Op, void(BOOST_PP_ENUM_BINARY_PARAMS(N, U, RREF u)) >::type call( const Op& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, U, RREF arg)) { ::boost::type_erasure::require_match(f BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg)); return ::boost::type_erasure::unchecked_call(f BOOST_TYPE_ERASURE_FORWARD_ARGS(N, U, arg)); } #endif #undef RREF #undef BOOST_TYPE_ERASURE_FORWARD_ARGS #undef BOOST_TYPE_ERASURE_FORWARD_ARGS_I #undef BOOST_TYPE_ERASURE_GET_TABLE #undef BOOST_TYPE_ERASURE_CONVERT_ARG #undef N #endif