diff options
Diffstat (limited to 'boost/type_erasure')
40 files changed, 2916 insertions, 302 deletions
diff --git a/boost/type_erasure/any.hpp b/boost/type_erasure/any.hpp index 3ed0243498..2505c96908 100644 --- a/boost/type_erasure/any.hpp +++ b/boost/type_erasure/any.hpp @@ -12,6 +12,9 @@ #define BOOST_TYPE_ERASURE_ANY_HPP_INCLUDED #include <algorithm> +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# include <utility> // std::forward, std::move +#endif #include <boost/config.hpp> #include <boost/utility/enable_if.hpp> #include <boost/utility/addressof.hpp> @@ -20,7 +23,8 @@ #include <boost/mpl/or.hpp> #include <boost/mpl/pair.hpp> #include <boost/mpl/map.hpp> -#include <boost/mpl/fold.hpp> +#include <boost/mpl/reverse_fold.hpp> +#include <boost/type_traits/decay.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/is_same.hpp> @@ -44,9 +48,18 @@ #include <boost/type_erasure/relaxed.hpp> #include <boost/type_erasure/param.hpp> +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4355) +#pragma warning(disable:4521) +#pragma warning(disable:4522) // multiple assignment operators specified +#endif + namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class Sig> struct constructible; @@ -56,17 +69,48 @@ struct destructible; template<class T, class U> struct assignable; +#endif + namespace detail { +#if defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template<class Concept, class Base, class ID> +struct choose_concept_interface +{ + typedef ::boost::type_erasure::concept_interface<Concept, Base, ID> type; +}; + +#else + +struct default_concept_interface +{ + template<class Concept, class Base, class ID> + using apply = ::boost::type_erasure::concept_interface<Concept, Base, ID>; +}; + +default_concept_interface boost_type_erasure_find_interface(...); + +template<class Concept, class Base, class ID> +struct choose_concept_interface +{ + typedef decltype(boost_type_erasure_find_interface(::boost::declval<Concept>())) finder; + typedef typename finder::template apply<Concept, Base, ID> type; +}; + +#endif + +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + template<class Derived, class Concept, class T> struct compute_bases { - typedef typename ::boost::mpl::fold< + typedef typename ::boost::mpl::reverse_fold< typename ::boost::type_erasure::detail::collect_concepts< Concept >::type, ::boost::type_erasure::any_base<Derived>, - ::boost::type_erasure::concept_interface< + ::boost::type_erasure::detail::choose_concept_interface< ::boost::mpl::_2, ::boost::mpl::_1, T @@ -74,6 +118,30 @@ struct compute_bases >::type type; }; +#else + +template<class ID> +struct compute_bases_f +{ + template<class Concept, class Base> + using apply = typename ::boost::type_erasure::detail::choose_concept_interface<Concept, Base, ID>::type; +}; + +template<class Derived, class Concept, class T> +using compute_bases_t = + ::boost::mp11::mp_reverse_fold< + typename ::boost::type_erasure::detail::collect_concepts_t< + Concept + >, + ::boost::type_erasure::any_base<Derived>, + ::boost::type_erasure::detail::compute_bases_f<T>::template apply + >; + +template<class Derived, class Concept, class T> +using compute_bases = ::boost::mpl::identity< ::boost::type_erasure::detail::compute_bases_t<Derived, Concept, T> >; + +#endif + template<class T> T make(T*) { return T(); } @@ -90,6 +158,22 @@ no check_overload(const void*); struct fallback {}; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template<class T> +fallback make_fallback(T&&, boost::mpl::false_) +{ + return fallback(); +} + +template<class T> +T&& make_fallback(T&& arg, boost::mpl::true_) +{ + return std::forward<T>(arg); +} + +#else + template<class T> fallback make_fallback(const T&, boost::mpl::false_) { @@ -102,20 +186,470 @@ const T& make_fallback(const T& arg, boost::mpl::true_) return arg; } +#endif + template<class T> struct is_any : ::boost::mpl::false_ {}; template<class Concept, class T> struct is_any<any<Concept, T> > : ::boost::mpl::true_ {}; +#ifdef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS + +template<class Any, class... U> +struct has_constructor : + ::boost::mpl::bool_< + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<Any&>(). + _boost_type_erasure_deduce_constructor(::boost::declval<U>()...) + ) + ) == sizeof(::boost::type_erasure::detail::yes) + > +{}; + +template<class Any> +using has_copy_constructor = + ::boost::type_erasure::is_subconcept< + ::boost::type_erasure::constructible< + typename ::boost::type_erasure::placeholder_of<Any>::type(typename ::boost::type_erasure::placeholder_of<Any>::type const&) + >, + typename ::boost::type_erasure::concept_of<Any>::type + >; + +template<class Any> +using has_move_constructor = + ::boost::type_erasure::is_subconcept< + ::boost::type_erasure::constructible< + typename ::boost::type_erasure::placeholder_of<Any>::type(typename ::boost::type_erasure::placeholder_of<Any>::type &&) + >, + typename ::boost::type_erasure::concept_of<Any>::type + >; + +template<class Any> +using has_mutable_copy_constructor = + ::boost::type_erasure::is_subconcept< + ::boost::type_erasure::constructible< + typename ::boost::type_erasure::placeholder_of<Any>::type(typename ::boost::type_erasure::placeholder_of<Any>::type &) + >, + typename ::boost::type_erasure::concept_of<Any>::type + >; + +struct empty {}; + +template<class T> +struct is_binding_arg : ::boost::mpl::false_ {}; +template<class T> +struct is_binding_arg<binding<T> > : ::boost::mpl::true_ {}; +template<class T> +struct is_binding_arg<binding<T>&&> : ::boost::mpl::true_ {}; +template<class T> +struct is_binding_arg<binding<T>&> : ::boost::mpl::true_ {}; +template<class T> +struct is_binding_arg<binding<T> const&> : ::boost::mpl::true_ {}; + +template<class T> +struct is_static_binding_arg : ::boost::mpl::false_ {}; +template<class T> +struct is_static_binding_arg<static_binding<T> > : ::boost::mpl::true_ {}; +template<class T> +struct is_static_binding_arg<static_binding<T>&&> : ::boost::mpl::true_ {}; +template<class T> +struct is_static_binding_arg<static_binding<T>&> : ::boost::mpl::true_ {}; +template<class T> +struct is_static_binding_arg<static_binding<T> const&> : ::boost::mpl::true_ {}; + +template<class T> +struct is_any_arg : ::boost::mpl::false_ {}; +template<class Concept, class T> +struct is_any_arg<any<Concept, T> > : ::boost::mpl::true_ {}; +template<class Concept, class T> +struct is_any_arg<any<Concept, T>&&> : ::boost::mpl::true_ {}; +template<class Concept, class T> +struct is_any_arg<any<Concept, T>&> : ::boost::mpl::true_ {}; +template<class Concept, class T> +struct is_any_arg<any<Concept, T> const&> : ::boost::mpl::true_ {}; + +template<class T> +struct safe_concept_of; +template<class Concept, class T> +struct safe_concept_of<any<Concept, T> > { typedef Concept type; }; +template<class Concept, class T> +struct safe_concept_of<any<Concept, T>&&> { typedef Concept type; }; +template<class Concept, class T> +struct safe_concept_of<any<Concept, T>&> { typedef Concept type; }; +template<class Concept, class T> +struct safe_concept_of<any<Concept, T> const&> { typedef Concept type; }; + +template<class T> +struct safe_placeholder_of; +template<class Concept, class T> +struct safe_placeholder_of<any<Concept, T> > { typedef T type; }; +template<class Concept, class T> +struct safe_placeholder_of<any<Concept, T>&&> { typedef T type; }; +template<class Concept, class T> +struct safe_placeholder_of<any<Concept, T>&> { typedef T type; }; +template<class Concept, class T> +struct safe_placeholder_of<any<Concept, T> const&> { typedef T type; }; + +template<class T> +using safe_placeholder_t = ::boost::remove_cv_t< ::boost::remove_reference_t<typename safe_placeholder_of<T>::type> >; + } -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4355) -#pragma warning(disable:4521) +// Enables or deletes the copy/move constructors depending on the Concept. +template<class Base, class Enable = void> +struct any_constructor_control : Base +{ + using Base::Base; +}; + +template<class Base> +struct any_constructor_control< + Base, + typename boost::enable_if_c< + !::boost::type_erasure::detail::has_copy_constructor<Base>::value && + ::boost::type_erasure::detail::has_move_constructor<Base>::value && + ::boost::type_erasure::detail::has_mutable_copy_constructor<Base>::value + >::type +> : Base +{ + using Base::Base; + any_constructor_control() = default; + any_constructor_control(any_constructor_control&) = default; + any_constructor_control(any_constructor_control&&) = default; + any_constructor_control& operator=(any_constructor_control const& other) { static_cast<Base&>(*this) = static_cast<Base const&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control & other) { static_cast<Base&>(*this) = static_cast<Base&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control &&) = default; +}; + +template<class Base> +struct any_constructor_control< + Base, + typename boost::enable_if_c< + !::boost::type_erasure::detail::has_copy_constructor<Base>::value && + !::boost::type_erasure::detail::has_move_constructor<Base>::value && + ::boost::type_erasure::detail::has_mutable_copy_constructor<Base>::value + >::type +> : Base +{ + using Base::Base; + any_constructor_control() = default; + any_constructor_control(any_constructor_control&) = default; + any_constructor_control(any_constructor_control&&) = delete; + any_constructor_control& operator=(any_constructor_control const& other) { static_cast<Base&>(*this) = static_cast<Base const&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control & other) { static_cast<Base&>(*this) = static_cast<Base&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control &&) = default; +}; + +template<class Base> +struct any_constructor_control< + Base, + typename boost::enable_if_c< + !::boost::type_erasure::detail::has_copy_constructor<Base>::value && + ::boost::type_erasure::detail::has_move_constructor<Base>::value && + !::boost::type_erasure::detail::has_mutable_copy_constructor<Base>::value + >::type +> : Base +{ + using Base::Base; + any_constructor_control() = default; + any_constructor_control(any_constructor_control const&) = delete; + any_constructor_control(any_constructor_control&&) = default; + any_constructor_control& operator=(any_constructor_control const& other) { static_cast<Base&>(*this) = static_cast<Base const&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control & other) { static_cast<Base&>(*this) = static_cast<Base&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control &&) = default; +}; + +template<class Base> +struct any_constructor_control< + Base, + typename boost::enable_if_c< + !::boost::type_erasure::detail::has_copy_constructor<Base>::value && + !::boost::type_erasure::detail::has_move_constructor<Base>::value && + !::boost::type_erasure::detail::has_mutable_copy_constructor<Base>::value + >::type +> : Base +{ + using Base::Base; + any_constructor_control() = default; + any_constructor_control(any_constructor_control const&) = delete; + any_constructor_control(any_constructor_control&&) = delete; + any_constructor_control& operator=(any_constructor_control const& other) { static_cast<Base&>(*this) = static_cast<Base const&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control & other) { static_cast<Base&>(*this) = static_cast<Base&>(other); return *this; } + any_constructor_control& operator=(any_constructor_control &&) = default; +}; + +template<class Concept, class T> +struct any_constructor_impl : + ::boost::type_erasure::detail::compute_bases< + ::boost::type_erasure::any<Concept, T>, + Concept, + T + >::type +{ + typedef typename ::boost::type_erasure::detail::compute_bases< + ::boost::type_erasure::any<Concept, T>, + Concept, + T + >::type _boost_type_erasure_base; + // Internal constructors + typedef ::boost::type_erasure::binding<Concept> _boost_type_erasure_table_type; + any_constructor_impl(const ::boost::type_erasure::detail::storage& data_arg, const _boost_type_erasure_table_type& table_arg) + : _boost_type_erasure_table(table_arg), + _boost_type_erasure_data(data_arg) + {} + any_constructor_impl(::boost::type_erasure::detail::storage&& data_arg, const _boost_type_erasure_table_type& table_arg) + : _boost_type_erasure_table(table_arg), + _boost_type_erasure_data(data_arg) + {} + // default constructor + any_constructor_impl() + { + BOOST_MPL_ASSERT((::boost::type_erasure::is_relaxed<Concept>)); + _boost_type_erasure_data.data = 0; + } + // capturing constructor + template<class U, + typename ::boost::enable_if_c< + !::boost::type_erasure::detail::is_any_arg<U>::value && + !::boost::type_erasure::detail::is_binding_arg<U>::value && + !::boost::type_erasure::detail::is_static_binding_arg<U>::value + >::type* = nullptr + > + any_constructor_impl(U&& data_arg) + : _boost_type_erasure_table(( + BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, ::boost::decay_t<U>), + ::boost::type_erasure::make_binding< + ::boost::mpl::map1< ::boost::mpl::pair<T, ::boost::decay_t<U> > > + >() + )), + _boost_type_erasure_data(std::forward<U>(data_arg)) + {} + template<class U, class Map, + typename ::boost::enable_if_c< + !::boost::type_erasure::detail::is_any_arg<U>::value && + !::boost::type_erasure::detail::is_binding_arg<U>::value && + !::boost::type_erasure::detail::is_static_binding_arg<U>::value + >::type* = nullptr + > + any_constructor_impl(U&& data_arg, const static_binding<Map>& b) + : _boost_type_erasure_table(( + BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), + b + )), + _boost_type_erasure_data(std::forward<U>(data_arg)) + { + BOOST_MPL_ASSERT((::boost::is_same< + typename ::boost::mpl::at<Map, T>::type, ::boost::decay_t<U> >)); + } + // converting constructor + template<class U, + typename ::boost::enable_if_c< + ::boost::type_erasure::is_subconcept< + Concept, typename ::boost::type_erasure::detail::safe_concept_of<U>::type, + typename ::boost::mpl::if_c< ::boost::is_same<T, ::boost::type_erasure::detail::safe_placeholder_t<U> >::value, + void, + ::boost::mpl::map1< + ::boost::mpl::pair<T, ::boost::type_erasure::detail::safe_placeholder_t<U> > + > + >::type + >::value + >::type* = nullptr + > + any_constructor_impl(U&& other) + : _boost_type_erasure_table( + ::boost::type_erasure::detail::access::table(other), + typename ::boost::mpl::if_c< ::boost::is_same<T, ::boost::type_erasure::detail::safe_placeholder_t<U> >::value, +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + ::boost::type_erasure::detail::substitution_map< ::boost::mpl::map0<> >, +#else + ::boost::type_erasure::detail::make_identity_placeholder_map<Concept>, +#endif + ::boost::mpl::map1< + ::boost::mpl::pair< + T, + ::boost::type_erasure::detail::safe_placeholder_t<U> + > + > + >::type() + ), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor(std::forward<U>(other)) : 0 + ), std::forward<U>(other)) + ) + {} + template<class U, + typename ::boost::enable_if_c< + ::boost::type_erasure::detail::is_any_arg<U>::value + >::type* = nullptr + > + any_constructor_impl(U&& other, const binding<Concept>& binding_arg) + : _boost_type_erasure_table(binding_arg), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor(std::forward<U>(other)) : 0 + ), std::forward<U>(other)) + ) + {} + template<class U, class Map, + typename ::boost::enable_if_c< + ::boost::type_erasure::is_subconcept< + Concept, typename ::boost::type_erasure::detail::safe_concept_of<U>::type, + Map + >::value + >::type* = nullptr + > + any_constructor_impl(U&& other, const static_binding<Map>& binding_arg) + : _boost_type_erasure_table(::boost::type_erasure::detail::access::table(other), binding_arg), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor(std::forward<U>(other)) : 0 + ), std::forward<U>(other)) + ) + {} + // copy and move constructors are a special case of the converting + // constructors, but must be defined separately to keep C++ happy. + any_constructor_impl(const any_constructor_impl& other) + : _boost_type_erasure_table( + ::boost::type_erasure::detail::access::table(other) + ), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor( + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type const&>(other)) : 0 + ), other) + ) + {} + any_constructor_impl(any_constructor_impl& other) + : _boost_type_erasure_table( + ::boost::type_erasure::detail::access::table(other) + ), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor( + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type &>(other)) : 0 + ), other) + ) + {} + any_constructor_impl(any_constructor_impl&& other) + : _boost_type_erasure_table( + ::boost::type_erasure::detail::access::table(other) + ), + _boost_type_erasure_data(::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? other._boost_type_erasure_deduce_constructor( + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type &&>(other)) : 0 + ), std::move(other)) + ) + {} + + template<class R, class... A, class... U> + const _boost_type_erasure_table_type& _boost_type_erasure_extract_table( + ::boost::type_erasure::constructible<R(A...)>*, + U&&... u) + { + return *::boost::type_erasure::detail::extract_table(static_cast<void(*)(A...)>(0), u...); + } + // forwarding constructor + template<class... U, + typename ::boost::enable_if_c< + ::boost::type_erasure::detail::has_constructor<any_constructor_impl, U...>::value + >::type* = nullptr + > + explicit any_constructor_impl(U&&... u) + : _boost_type_erasure_table( + _boost_type_erasure_extract_table( + false? this->_boost_type_erasure_deduce_constructor(std::forward<U>(u)...) : 0, + std::forward<U>(u)... + ) + ), + _boost_type_erasure_data( + ::boost::type_erasure::call( + ::boost::type_erasure::detail::make( + false? this->_boost_type_erasure_deduce_constructor(std::forward<U>(u)...) : 0 + ), + std::forward<U>(u)... + ) + ) + {} + template<class... U, + typename ::boost::enable_if_c< + ::boost::type_erasure::detail::has_constructor<any_constructor_impl, U...>::value + >::type* = nullptr + > + explicit any_constructor_impl(const binding<Concept>& binding_arg, U&&... u) + : _boost_type_erasure_table(binding_arg), + _boost_type_erasure_data( + ::boost::type_erasure::call( + binding_arg, + ::boost::type_erasure::detail::make( + false? this->_boost_type_erasure_deduce_constructor(std::forward<U>(u)...) : 0 + ), + std::forward<U>(u)... + ) + ) + {} + + // The assignment operator and destructor must be defined here rather + // than in any to avoid implicitly deleting the move constructor. + + any_constructor_impl& operator=(const any_constructor_impl& other) + { + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type*>(this)->_boost_type_erasure_resolve_assign( + static_cast<const typename _boost_type_erasure_base::_boost_type_erasure_derived_type&>(other)); + return *this; + } + + any_constructor_impl& operator=(any_constructor_impl& other) + { + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type*>(this)->_boost_type_erasure_resolve_assign( + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type&>(other)); + return *this; + } + + any_constructor_impl& operator=(any_constructor_impl&& other) + { + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type*>(this)->_boost_type_erasure_resolve_assign( + static_cast<typename _boost_type_erasure_base::_boost_type_erasure_derived_type&&>(other)); + return *this; + } + + ~any_constructor_impl() + { + _boost_type_erasure_table.template find< + ::boost::type_erasure::destructible<T> + >()(_boost_type_erasure_data); + } + +protected: + friend struct ::boost::type_erasure::detail::access; + + _boost_type_erasure_table_type _boost_type_erasure_table; + ::boost::type_erasure::detail::storage _boost_type_erasure_data; +}; + +namespace detail { + #endif +template<class T> +struct is_rvalue_for_any : + ::boost::mpl::not_< + ::boost::is_lvalue_reference<T> + > +{}; + +template<class C, class P> +struct is_rvalue_for_any<any<C, P> > : + ::boost::mpl::not_< + ::boost::is_lvalue_reference<P> + > +{}; + +} + /** * The class template @ref any can store any object that * models a specific \Concept. It dispatches all @@ -129,16 +663,37 @@ struct is_any<any<Concept, T> > : ::boost::mpl::true_ {}; */ template<class Concept, class T = _self> class any : +#ifdef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS + public ::boost::type_erasure::any_constructor_control< + ::boost::type_erasure::any_constructor_impl< + + Concept, + T + > + > +#else public ::boost::type_erasure::detail::compute_bases< ::boost::type_erasure::any<Concept, T>, Concept, T >::type +#endif { typedef ::boost::type_erasure::binding<Concept> table_type; public: /** INTERNAL ONLY */ typedef Concept _boost_type_erasure_concept_type; + +#if defined(BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS) + using _boost_type_erasure_base = ::boost::type_erasure::any_constructor_control< + ::boost::type_erasure::any_constructor_impl< + Concept, + T + > + >; + using _boost_type_erasure_base::_boost_type_erasure_base; +#else + /** INTERNAL ONLY */ any(const ::boost::type_erasure::detail::storage& data_arg, const table_type& table_arg) : table(table_arg), @@ -183,7 +738,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, U), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, U> > + ::boost::mpl::map1< ::boost::mpl::pair<T, U> > >() )), data(data_arg) @@ -224,7 +779,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, typename ::boost::remove_cv<typename ::boost::remove_reference<U>::type>::type), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, typename ::boost::remove_cv<typename ::boost::remove_reference<U>::type>::type> > + ::boost::mpl::map1< ::boost::mpl::pair<T, typename ::boost::remove_cv<typename ::boost::remove_reference<U>::type>::type> > >() )), data(std::forward<U>(data_arg)) @@ -269,7 +824,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, U*), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, U*> > + ::boost::mpl::map1< ::boost::mpl::pair<T, U*> > >() )), data(data_arg) @@ -307,7 +862,7 @@ public: * * \param other The object to make a copy of. * - * \pre @c Concept must contain @ref constructible<T(const T&)>. + * \pre @c Concept must contain @ref constructible "constructible<T(const T&)>". * \pre @c Concept must not refer to any non-deduced placeholder besides @c T. * \pre After substituting @c T for @c Tag2, the requirements of * @c Concept2 must be a superset of the requirements of @@ -320,7 +875,7 @@ public: any(const any<Concept2, Tag2>& other) : table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_const< @@ -344,7 +899,7 @@ public: * \param binding Specifies the mapping between the placeholders * used by the two concepts. * - * \pre @c Concept must contain @ref constructible<T(const T&)>. + * \pre @c Concept must contain @ref constructible "constructible<T(const T&)>". * \pre @c Map must be an MPL map with keys for all the non-deduced * placeholders used by @c Concept and values for the corresponding * placeholders in @c Concept2. @@ -372,7 +927,7 @@ public: * \param other The object to make a copy of. * \param binding Specifies the bindings of placeholders to actual types. * - * \pre @c Concept must contain @ref constructible<T(const T&)>. + * \pre @c Concept must contain @ref constructible "constructible<T(const T&)>". * \pre The type stored in @c other must match the type expected by * @c binding. * @@ -467,7 +1022,7 @@ public: any(any<Concept2, Tag2>& other) : table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_const< @@ -486,7 +1041,7 @@ public: any(any<Concept2, Tag2>&& other) : table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_const< @@ -884,7 +1439,7 @@ public: #endif -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template<class R, class... A, class... U> const table_type& _boost_type_erasure_extract_table( @@ -926,7 +1481,7 @@ public: ) {} - // disambiguate + // disambiguating overloads template<class U0, class... U> any(binding<Concept>& binding_arg, U0&& u0, U&&... u) : table(binding_arg), @@ -961,28 +1516,44 @@ public: #endif #endif - - /** - * Assigns to an @ref any. - * - * If an appropriate overload of @ref assignable is not available - * and @ref relaxed is in @c Concept, falls back on - * constructing from @c other. - * - * \throws Whatever the assignment operator of the contained - * type throws. When falling back on construction, - * throws @c std::bad_alloc or whatever the copy - * constructor of the contained type throws. In - * this case assignment provides the strong exception - * guarantee. When calling the assignment operator - * of the contained type, the exception guarantee is - * whatever the contained type provides. - */ + + /** INTERNAL ONLY */ any& operator=(const any& other) { _boost_type_erasure_resolve_assign(other); return *this; } + /** INTERNAL ONLY */ + any& operator=(any& other) + { + _boost_type_erasure_resolve_assign(other); + return *this; + } + +#endif // BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template<class U> + any& operator=(U& other) + { + _boost_type_erasure_resolve_assign(other); + return *this; + } + template<class U> + any& operator=(const U& other) + { + _boost_type_erasure_resolve_assign(other); + return *this; + } +#else +#ifndef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS + /** INTERNAL ONLY */ + any& operator=(any&& other) + { + _boost_type_erasure_resolve_assign(std::move(other)); + return *this; + } +#endif /** * Assigns to an @ref any. * @@ -990,45 +1561,123 @@ public: * and @ref relaxed is in @c Concept, falls back on * constructing from @c other. * + * \note If @c U is an @ref any, then this can decide dynamically + * whether to use construction based on the type stored in other. + * * \throws Whatever the assignment operator of the contained * type throws. When falling back on construction, - * throws @c std::bad_alloc or whatever the copy + * throws @c std::bad_alloc or whatever the move (or copy) * constructor of the contained type throws. In - * this case assignment provides the strong exception - * guarantee. When calling an assignment operator + * this case move assignment provides the strong exception + * guarantee. When calling a (move) assignment operator * of the contained type, the exception guarantee is * whatever the contained type provides. */ template<class U> - any& operator=(const U& other) + any& operator=(U&& other) { - _boost_type_erasure_resolve_assign(other); + _boost_type_erasure_resolve_assign(std::forward<U>(other)); return *this; } +#endif + +#ifndef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS /** * \pre @c Concept includes @ref destructible "destructible<T>". */ ~any() { - table.template find<destructible<T> >()(data); + ::boost::type_erasure::detail::access::table(*this).template find< + ::boost::type_erasure::destructible<T> + >()(::boost::type_erasure::detail::access::data(*this)); } +#endif -#ifndef BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS /** INTERNAL ONLY */ - operator param<Concept, T&>() & { return param<Concept, T&>(data, table); } + operator param<Concept, T&>() & + { + return param<Concept, T&>( + boost::type_erasure::detail::access::data(*this), + boost::type_erasure::detail::access::table(*this)); + } /** INTERNAL ONLY */ - operator param<Concept, T&&>() && { return param<Concept, T&&>(data, table); } + operator param<Concept, T&&>() && { + return param<Concept, T&&>( + boost::type_erasure::detail::access::data(*this), + boost::type_erasure::detail::access::table(*this)); + } #endif private: +#ifndef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS /** INTERNAL ONLY */ void _boost_type_erasure_swap(any& other) { ::std::swap(data, other.data); ::std::swap(table, other.table); } +#else + void _boost_type_erasure_swap(any& other) + { + ::std::swap(this->_boost_type_erasure_data, other._boost_type_erasure_data); + ::std::swap(this->_boost_type_erasure_table, other._boost_type_erasure_table); + } +#endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_resolve_assign(Other&& other) + { + _boost_type_erasure_assign_impl( + std::forward<Other>(other), + false? this->_boost_type_erasure_deduce_assign( + ::boost::type_erasure::detail::make_fallback( + std::forward<Other>(other), + ::boost::mpl::bool_< + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<any&>(). + _boost_type_erasure_deduce_assign(std::forward<Other>(other)) + ) + ) == sizeof(::boost::type_erasure::detail::yes) + >() + ) + ) : 0, + ::boost::type_erasure::is_relaxed<Concept>() + ); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + ::boost::mpl::false_) + { + ::boost::type_erasure::call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + ::boost::mpl::true_) + { + ::boost::type_erasure::call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_assign_impl( + Other&& other, + const void*, + ::boost::mpl::true_) + { + any temp(std::forward<Other>(other)); + _boost_type_erasure_swap(temp); + } +#else /** INTERNAL ONLY */ template<class Other> - void _boost_type_erasure_resolve_assign(const Other& other) + void _boost_type_erasure_resolve_assign(Other& other) { _boost_type_erasure_assign_impl( other, @@ -1051,7 +1700,7 @@ private: /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const assignable<T, U>*, ::boost::mpl::false_) { @@ -1060,7 +1709,7 @@ private: /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const assignable<T, U>*, ::boost::mpl::true_) { @@ -1069,17 +1718,122 @@ private: /** INTERNAL ONLY */ template<class Other> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const void*, ::boost::mpl::true_) { any temp(other); _boost_type_erasure_swap(temp); } +#endif /** INTERNAL ONLY */ template<class Concept2, class Tag2> void _boost_type_erasure_resolve_assign(const any<Concept2, Tag2>& other) { + _boost_type_erasure_resolve_assign_any(other); + } + /** INTERNAL ONLY */ + template<class Concept2, class Tag2> + void _boost_type_erasure_resolve_assign(any<Concept2, Tag2>& other) + { + _boost_type_erasure_resolve_assign_any(other); + } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /** INTERNAL ONLY */ + template<class Concept2, class Tag2> + void _boost_type_erasure_resolve_assign(any<Concept2, Tag2>&& other) + { + _boost_type_erasure_resolve_assign_any(std::move(other)); + } + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_resolve_assign_any(Other&& other) + { + _boost_type_erasure_assign_impl( + std::forward<Other>(other), + false? this->_boost_type_erasure_deduce_assign( + ::boost::type_erasure::detail::make_fallback( + std::forward<Other>(other), + ::boost::mpl::bool_< + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<any&>(). + _boost_type_erasure_deduce_assign(std::forward<Other>(other)) + ) + ) == sizeof(::boost::type_erasure::detail::yes) + >() + ) + ) : 0, + false? this->_boost_type_erasure_deduce_constructor( + ::boost::type_erasure::detail::make_fallback( + std::forward<Other>(other), + ::boost::mpl::bool_< + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<any&>(). + _boost_type_erasure_deduce_constructor(std::forward<Other>(other)) + ) + ) == sizeof(::boost::type_erasure::detail::yes) + >() + ) + ) : 0, + ::boost::type_erasure::is_relaxed<Concept>() + ); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + const void*, + ::boost::mpl::false_) + { + ::boost::type_erasure::call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + const void*, + ::boost::mpl::true_) + { + ::boost::type_erasure::call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + /** INTERNAL ONLY */ + template<class Other, class Sig> + void _boost_type_erasure_assign_impl( + Other&& other, + const void*, + const constructible<Sig>*, + ::boost::mpl::true_) + { + any temp(std::forward<Other>(other)); + _boost_type_erasure_swap(temp); + } + /** INTERNAL ONLY */ + template<class Other, class U, class Sig> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + const constructible<Sig>*, + ::boost::mpl::true_) + { + if(::boost::type_erasure::check_match(assignable<T, U>(), *this, other)) // const reference to other is enough! + { + ::boost::type_erasure::unchecked_call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + else + { + any temp(std::forward<Other>(other)); + _boost_type_erasure_swap(temp); + } + } +#else + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_resolve_assign_any(Other& other) + { _boost_type_erasure_assign_impl( other, false? this->_boost_type_erasure_deduce_assign( @@ -1114,7 +1868,7 @@ private: /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const assignable<T, U>*, const void*, ::boost::mpl::false_) @@ -1124,7 +1878,7 @@ private: /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const assignable<T, U>*, const void*, ::boost::mpl::true_) @@ -1134,7 +1888,7 @@ private: /** INTERNAL ONLY */ template<class Other, class Sig> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const void*, const constructible<Sig>*, ::boost::mpl::true_) @@ -1145,7 +1899,7 @@ private: /** INTERNAL ONLY */ template<class Other, class U, class Sig> void _boost_type_erasure_assign_impl( - const Other& other, + Other& other, const assignable<T, U>*, const constructible<Sig>*, ::boost::mpl::true_) @@ -1160,11 +1914,17 @@ private: _boost_type_erasure_swap(temp); } } +#endif friend struct ::boost::type_erasure::detail::access; +#ifndef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS // The table has to be initialized first for exception // safety in some constructors. table_type table; ::boost::type_erasure::detail::storage data; +#else + template<class Concept2, class T2> + friend struct ::boost::type_erasure::any_constructor_impl; +#endif }; template<class Concept, class T> @@ -1209,7 +1969,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, U), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, U> > + ::boost::mpl::map1< ::boost::mpl::pair<T, U> > >() )) { @@ -1293,7 +2053,7 @@ public: : data(::boost::type_erasure::detail::access::data(other)), table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, Tag2 @@ -1326,7 +2086,7 @@ public: : data(::boost::type_erasure::detail::access::data(other)), table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_reference<Tag2>::type @@ -1432,26 +2192,27 @@ public: table(binding_arg) {} - /** - * Assigns to an @ref any. - * - * If an appropriate overload of @ref assignable is not available - * and @ref relaxed is in @c Concept, falls back on - * constructing from @c other. - * - * \throws Whatever the assignment operator of the contained - * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment - * provides the strong exception guarantee. When - * calling the assignment operator of the contained type, - * the exception guarantee is whatever the contained type provides. - */ + /** INTERNAL ONLY */ any& operator=(const any& other) { _boost_type_erasure_resolve_assign(other); return *this; } + /** INTERNAL ONLY */ + any& operator=(any& other) + { + _boost_type_erasure_resolve_assign(other); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /** INTERNAL ONLY */ + any& operator=(any&& other) + { + _boost_type_erasure_resolve_assign(std::move(other)); + return *this; + } /** * Assigns to an @ref any. * @@ -1461,40 +2222,35 @@ public: * * \throws Whatever the assignment operator of the contained * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment + * can only throw @c std::bad_alloc if @c U is an @ref any + * that uses a different @c Concept. In this case assignment * provides the strong exception guarantee. When * calling the assignment operator of the contained type, * the exception guarantee is whatever the contained type provides. */ template<class U> + any& operator=(U&& other) + { + _boost_type_erasure_resolve_assign(std::forward<U>(other)); + return *this; + } +#else + template<class U> any& operator=(U& other) { _boost_type_erasure_resolve_assign(other); return *this; } - /** - * Assigns to an @ref any. - * - * If an appropriate overload of @ref assignable is not available - * and @ref relaxed is in @c Concept, falls back on - * constructing from @c other. - * - * \throws Whatever the assignment operator of the contained - * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment - * provides the strong exception guarantee. When - * calling the assignment operator of the contained type, - * the exception guarantee is whatever the contained type provides. - */ template<class U> any& operator=(const U& other) { _boost_type_erasure_resolve_assign(other); return *this; } +#endif -#ifndef BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS /** INTERNAL ONLY */ operator param<Concept, T&>() const { return param<Concept, T&>(data, table); } #endif @@ -1506,6 +2262,71 @@ private: ::std::swap(data, other.data); ::std::swap(table, other.table); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_resolve_assign(Other&& other) + { + _boost_type_erasure_assign_impl( + std::forward<Other>(other), + false? this->_boost_type_erasure_deduce_assign( + ::boost::type_erasure::detail::make_fallback( + std::forward<Other>(other), + ::boost::mpl::bool_< + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<any&>(). + _boost_type_erasure_deduce_assign(std::forward<Other>(other)) + ) + ) == sizeof(::boost::type_erasure::detail::yes) + >() + ) + ) : 0, + ::boost::mpl::and_< + ::boost::type_erasure::is_relaxed<Concept>, + ::boost::is_convertible<Other, any> +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1900)) + , ::boost::mpl::not_< + ::boost::type_erasure::detail::is_rvalue_for_any<Other> + > +#endif + >() + ); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + ::boost::mpl::false_) + { + ::boost::type_erasure::call(assignable<T, U>(), *this, std::forward<Other>(other)); + } + /** INTERNAL ONLY */ + template<class Other, class U> + void _boost_type_erasure_assign_impl( + Other&& other, + const assignable<T, U>*, + ::boost::mpl::true_) + { + if(::boost::type_erasure::check_match(assignable<T, U>(), *this, other)) { + ::boost::type_erasure::unchecked_call(assignable<T, U>(), *this, std::forward<Other>(other)); + } else { + any temp(std::forward<Other>(other)); + _boost_type_erasure_swap(temp); + } + } + /** INTERNAL ONLY */ + template<class Other> + void _boost_type_erasure_assign_impl( + Other&& other, + const void*, + ::boost::mpl::true_) + { + any temp(std::forward<Other>(other)); + _boost_type_erasure_swap(temp); + } +#else /** INTERNAL ONLY */ template<class Other> void _boost_type_erasure_resolve_assign(Other& other) @@ -1525,7 +2346,10 @@ private: >() ) ) : 0, - ::boost::type_erasure::is_relaxed<Concept>() + ::boost::mpl::and_< + ::boost::type_erasure::is_relaxed<Concept>, + ::boost::is_convertible<Other&, any> + >() ); } /** INTERNAL ONLY */ @@ -1561,6 +2385,7 @@ private: any temp(other); _boost_type_erasure_swap(temp); } +#endif friend struct ::boost::type_erasure::detail::access; ::boost::type_erasure::detail::storage data; @@ -1604,7 +2429,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, U), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, U> > + ::boost::mpl::map1< ::boost::mpl::pair<T, U> > >() )) { @@ -1701,7 +2526,7 @@ public: : data(::boost::type_erasure::detail::access::data(other)), table( ::boost::type_erasure::detail::access::table(other), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_const< @@ -1780,7 +2605,7 @@ public: return *this; } -#ifndef BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS /** INTERNAL ONLY */ operator param<Concept, const T&>() const { return param<Concept, const T&>(data, table); } #endif @@ -1841,7 +2666,7 @@ public: : table(( BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, T, U), ::boost::type_erasure::make_binding< - ::boost::mpl::map< ::boost::mpl::pair<T, U> > + ::boost::mpl::map1< ::boost::mpl::pair<T, U> > >() )) { @@ -1926,7 +2751,7 @@ public: : data(::boost::type_erasure::detail::access::data(other)), table( std::move(::boost::type_erasure::detail::access::table(other)), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, Tag2 @@ -1959,7 +2784,7 @@ public: : data(::boost::type_erasure::detail::access::data(other)), table( std::move(::boost::type_erasure::detail::access::table(other)), - ::boost::mpl::map< + ::boost::mpl::map1< ::boost::mpl::pair< T, typename ::boost::remove_reference<Tag2>::type @@ -2065,20 +2890,7 @@ public: table(binding_arg) {} - /** - * Assigns to an @ref any. - * - * If an appropriate overload of @ref assignable is not available - * and @ref relaxed is in @c Concept, falls back on - * constructing from @c other. - * - * \throws Whatever the assignment operator of the contained - * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment - * provides the strong exception guarantee. When - * calling the assignment operator of the contained type, - * the exception guarantee is whatever the contained type provides. - */ + /** INTERNAL ONLY */ any& operator=(const any& other) { _boost_type_erasure_resolve_assign(other); @@ -2094,40 +2906,20 @@ public: * * \throws Whatever the assignment operator of the contained * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment + * can only throw @c std::bad_alloc if @c U is an @ref any + * that uses a different @c Concept. In this case assignment * provides the strong exception guarantee. When * calling the assignment operator of the contained type, * the exception guarantee is whatever the contained type provides. */ template<class U> - any& operator=(U& other) + any& operator=(U&& other) { - _boost_type_erasure_resolve_assign(other); + _boost_type_erasure_resolve_assign(std::forward<U>(other)); return *this; } - /** - * Assigns to an @ref any. - * - * If an appropriate overload of @ref assignable is not available - * and @ref relaxed is in @c Concept, falls back on - * constructing from @c other. - * - * \throws Whatever the assignment operator of the contained - * type throws. When falling back on construction, - * throws @c std::bad_alloc. In this case assignment - * provides the strong exception guarantee. When - * calling the assignment operator of the contained type, - * the exception guarantee is whatever the contained type provides. - */ - template<class U> - any& operator=(const U& other) - { - _boost_type_erasure_resolve_assign(other); - return *this; - } - -#ifndef BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS /** INTERNAL ONLY */ operator param<Concept, T&&>() const { return param<Concept, T&&>(data, table); } #endif @@ -2141,57 +2933,68 @@ private: } /** INTERNAL ONLY */ template<class Other> - void _boost_type_erasure_resolve_assign(Other& other) + void _boost_type_erasure_resolve_assign(Other&& other) { _boost_type_erasure_assign_impl( - other, + std::forward<Other>(other), false? this->_boost_type_erasure_deduce_assign( ::boost::type_erasure::detail::make_fallback( - other, + std::forward<Other>(other), ::boost::mpl::bool_< - sizeof( - ::boost::type_erasure::detail::check_overload( - ::boost::declval<any&>(). - _boost_type_erasure_deduce_assign(other) - ) + sizeof( + ::boost::type_erasure::detail::check_overload( + ::boost::declval<any&>(). + _boost_type_erasure_deduce_assign(std::forward<Other>(other)) + ) ) == sizeof(::boost::type_erasure::detail::yes) >() ) ) : 0, - ::boost::type_erasure::is_relaxed<Concept>() + ::boost::mpl::and_< + ::boost::type_erasure::is_relaxed<Concept>, + ::boost::is_convertible<Other, any> + >() ); } /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - Other& other, + Other&& other, const assignable<T, U>*, ::boost::mpl::false_) { - ::boost::type_erasure::call(assignable<T, U>(), *this, other); + ::boost::type_erasure::call( + assignable<T, U>(), + // lose rvalueness of this + ::boost::type_erasure::param<Concept, T&>(data, table), + std::forward<Other>(other)); } /** INTERNAL ONLY */ template<class Other, class U> void _boost_type_erasure_assign_impl( - Other& other, + Other&& other, const assignable<T, U>*, ::boost::mpl::true_) { if(::boost::type_erasure::check_match(assignable<T, U>(), *this, other)) { - ::boost::type_erasure::unchecked_call(assignable<T, U>(), *this, other); + ::boost::type_erasure::unchecked_call( + assignable<T, U>(), + // lose rvalueness of this + ::boost::type_erasure::param<Concept, T&>(data, table), + std::forward<Other>(other)); } else { - any temp(other); + any temp(std::forward<Other>(other)); _boost_type_erasure_swap(temp); } } /** INTERNAL ONLY */ template<class Other> void _boost_type_erasure_assign_impl( - Other& other, + Other&& other, const void*, ::boost::mpl::true_) { - any temp(other); + any temp(std::forward<Other>(other)); _boost_type_erasure_swap(temp); } @@ -2202,6 +3005,17 @@ private: #endif +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES +template<class Concept, class T> +using any_ref = any<Concept, T&>; +template<class Concept, class T> +using any_cref = any<Concept, const T&>; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template<class Concept, class T> +using any_rvref = any<Concept, T&&>; +#endif +#endif + } } diff --git a/boost/type_erasure/any_cast.hpp b/boost/type_erasure/any_cast.hpp index ea8d66a9a9..939535c470 100644 --- a/boost/type_erasure/any_cast.hpp +++ b/boost/type_erasure/any_cast.hpp @@ -109,7 +109,7 @@ bool check_any_cast(const any<Concept, Tag>& arg) * \endcode * * \pre if @c arg is a pointer, @c T must be a pointer type. - * \pre @c Concept must contain @ref typeid_<tt><Tag></tt>. + * \pre @c Concept must contain @ref typeid_ "typeid_<Tag>". * * \throws bad_any_cast if @c arg doesn't contain * an object of type @c T and we're casting diff --git a/boost/type_erasure/builtin.hpp b/boost/type_erasure/builtin.hpp index 812b34face..7af5d84b23 100644 --- a/boost/type_erasure/builtin.hpp +++ b/boost/type_erasure/builtin.hpp @@ -12,10 +12,15 @@ #define BOOST_TYPE_ERASURE_BUILTIN_HPP_INCLUDED #include <boost/mpl/vector.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/is_reference.hpp> #include <boost/type_erasure/detail/storage.hpp> #include <boost/type_erasure/placeholder.hpp> #include <boost/type_erasure/constructible.hpp> #include <boost/type_erasure/rebind_any.hpp> +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# include <utility> // std::move +#endif #include <typeinfo> namespace boost { @@ -64,27 +69,60 @@ struct copy_constructible : ::boost::mpl::vector<constructible<T(const T&)>, destructible<T> > {}; +#ifdef BOOST_TYPE_ERASURE_DOXYGEN + /** * Enables assignment of @ref any types. */ -template<class T = _self, class U = T> +template<class T = _self, class U = const T&> struct assignable { - static void apply(T& dst, const U& src) { dst = src; } + static void apply(T& dst, U src); +}; + +#else + +/** + * Enables assignment of @ref any types. + */ +template<class T = _self, class U = const T&> +struct assignable : + ::boost::mpl::vector<assignable<T, const U&> > +{}; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +/** INTERNAL ONLY */ +template<class T, class U> +struct assignable<T, U&&> +{ + static void apply(T& dst, U&& src) { dst = std::forward<U>(src); } +}; + +#endif + +/** INTERNAL ONLY */ +template<class T, class U> +struct assignable<T, U&> +{ + static void apply(T& dst, U& src) { dst = src; } }; /** INTERNAL ONLY */ template<class T, class U, class Base> -struct concept_interface<assignable<T, U>, Base, T> : Base +struct concept_interface<assignable<T, U>, Base, T, + typename ::boost::enable_if_c< ::boost::is_reference<U>::value>::type> : Base { using Base::_boost_type_erasure_deduce_assign; assignable<T, U>* _boost_type_erasure_deduce_assign( - typename ::boost::type_erasure::rebind_any<Base, const U&>::type) + typename ::boost::type_erasure::as_param<Base, U>::type) { return 0; } }; +#endif + /** * Enables runtime type information. This is required * if you want to use \any_cast or \typeid_of. diff --git a/boost/type_erasure/call.hpp b/boost/type_erasure/call.hpp index 2a8ee2c580..8234862cae 100644 --- a/boost/type_erasure/call.hpp +++ b/boost/type_erasure/call.hpp @@ -42,12 +42,16 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class Concept, class Placeholder> class any; template<class Concept> class binding; +#endif + namespace detail { template<class T> @@ -293,6 +297,8 @@ namespace detail { template<class... T> void ignore(const T&...) {} +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + template<class R, class... T, class... U> const ::boost::type_erasure::binding< typename ::boost::type_erasure::detail::extract_concept<void(T...), U...>::type>* @@ -312,6 +318,29 @@ extract_table(R(*)(T...), const U&... arg) return result; } +#else + +template<class R, class... T, class... U> +const ::boost::type_erasure::binding< + ::boost::type_erasure::detail::extract_concept_t< ::boost::mp11::mp_list<T...>, ::boost::mp11::mp_list<U...> > >* +extract_table(R(*)(T...), const U&... arg) +{ + const ::boost::type_erasure::binding< + ::boost::type_erasure::detail::extract_concept_t< + ::boost::mp11::mp_list<T...>, ::boost::mp11::mp_list<U...> > >* 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<T>())...); + + BOOST_ASSERT(result != 0); + return result; +} + +#endif + template<class Sig, class Args, class Concept, bool ReturnsAny> struct call_impl_dispatch; @@ -354,6 +383,8 @@ struct call_impl<R(T...), void(U...), Concept, true> : { }; +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + template<class R, class... T, class... U> struct call_impl<R(T...), void(U...), void, true> : ::boost::type_erasure::detail::call_impl_dispatch< @@ -368,6 +399,24 @@ struct call_impl<R(T...), void(U...), void, true> : { }; +#else + +template<class R, class... T, class... U> +struct call_impl<R(T...), void(U...), void, true> : + ::boost::type_erasure::detail::call_impl_dispatch< + R(T...), + void(U...), + ::boost::type_erasure::detail::extract_concept_t< + ::boost::mp11::mp_list<T...>, + ::boost::mp11::mp_list< ::boost::remove_reference_t<U>...> + >, + ::boost::type_erasure::detail::is_placeholder_arg<R>::value + > +{ +}; + +#endif + } template< diff --git a/boost/type_erasure/check_match.hpp b/boost/type_erasure/check_match.hpp index d4c68f51bf..6f76edd4a5 100644 --- a/boost/type_erasure/check_match.hpp +++ b/boost/type_erasure/check_match.hpp @@ -33,12 +33,16 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class T> struct typeid_; template<class Concept> class binding; +#endif + namespace detail { template<class P, class T, class Table> @@ -94,8 +98,8 @@ bool check_match(const Op& f, U&&... args); namespace detail { -template<class Concept> -bool check_table(const ::boost::type_erasure::binding<Concept>* t, void(*)()) +template<class Concept, class R> +bool check_table(const ::boost::type_erasure::binding<Concept>* /*t*/, R(*)()) { return true; } @@ -134,6 +138,8 @@ bool check_match( arg...); } +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + template< class Op, class... U @@ -152,6 +158,42 @@ bool check_match( #else +namespace detail { + +template<class T> +struct get_args; + +template<class R, class ... T> +struct get_args<R(T...)> { typedef ::boost::mp11::mp_list<T...> type; }; + +template<class Sig> +using get_args_t = typename get_args<Sig>::type; + +} + +template< + class Op, + class... U +> +bool check_match( + const Op&, + U&&... arg) +{ + const ::boost::type_erasure::binding< + ::boost::type_erasure::detail::extract_concept_t< + ::boost::type_erasure::detail::get_args_t< + typename ::boost::type_erasure::detail::get_signature<Op>::type + >, + ::boost::mp11::mp_list< ::boost::remove_reference_t<U>...> > >* p = 0; + + return ::boost::type_erasure::detail::check_table( + p, static_cast<typename ::boost::type_erasure::detail::get_signature<Op>::type*>(0), arg...); +} + +#endif + +#else + #define BOOST_PP_FILENAME_1 <boost/type_erasure/check_match.hpp> #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY) #include BOOST_PP_ITERATE() diff --git a/boost/type_erasure/concept_of.hpp b/boost/type_erasure/concept_of.hpp index 43b4de52d7..f4b12dc743 100644 --- a/boost/type_erasure/concept_of.hpp +++ b/boost/type_erasure/concept_of.hpp @@ -11,15 +11,21 @@ #ifndef BOOST_TYPE_ERASURE_CONCEPT_OF_HPP_INCLUDED #define BOOST_TYPE_ERASURE_CONCEPT_OF_HPP_INCLUDED +#include <boost/config.hpp> + namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class Concept, class T> class any; template<class Concept, class T> class param; +#endif + /** * A metafunction returning the concept corresponding * to an @ref any. It will also work for all bases @@ -52,6 +58,13 @@ struct concept_of< ::boost::type_erasure::param<Concept, T> > typedef Concept type; }; +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +template<class T> +using concept_of_t = typename ::boost::type_erasure::concept_of<T>::type; + +#endif + } } diff --git a/boost/type_erasure/constructible.hpp b/boost/type_erasure/constructible.hpp index 5f1a413058..dd3c0f0004 100644 --- a/boost/type_erasure/constructible.hpp +++ b/boost/type_erasure/constructible.hpp @@ -41,7 +41,7 @@ struct get_null_vtable_entry; template<class C, class Sig> struct vtable_adapter; -}; +} #ifdef BOOST_TYPE_ERASURE_DOXYGEN @@ -88,7 +88,7 @@ struct concept_interface< using Base::_boost_type_erasure_deduce_constructor; ::boost::type_erasure::constructible<Tag(T...)>* _boost_type_erasure_deduce_constructor( - typename ::boost::type_erasure::as_param<Base, T>::type...) + typename ::boost::type_erasure::as_param<Base, T>::type...) const { return 0; } @@ -168,7 +168,7 @@ struct concept_interface< using Base::_boost_type_erasure_deduce_constructor; ::boost::type_erasure::constructible<Tag(BOOST_PP_ENUM_PARAMS(N, T))>* _boost_type_erasure_deduce_constructor( - BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_ARG_DECL, ~)) + BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_ARG_DECL, ~)) const { return 0; } diff --git a/boost/type_erasure/deduced.hpp b/boost/type_erasure/deduced.hpp index b9ed96094c..966c29bfc0 100644 --- a/boost/type_erasure/deduced.hpp +++ b/boost/type_erasure/deduced.hpp @@ -37,7 +37,11 @@ struct deduced : ::boost::type_erasure::placeholder ::boost::mpl::empty< typename ::boost::type_erasure::detail::get_placeholders< Metafunction, +#ifndef BOOST_TYPE_ERASURE_USE_MP11 ::boost::mpl::set0<> +#else + ::boost::mp11::mp_list<> +#endif >::type >, Metafunction, diff --git a/boost/type_erasure/derived.hpp b/boost/type_erasure/derived.hpp index 42316d2b57..844d9c2072 100644 --- a/boost/type_erasure/derived.hpp +++ b/boost/type_erasure/derived.hpp @@ -31,6 +31,13 @@ struct derived #endif }; +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +template<class T> +using derived_t = typename T::_boost_type_erasure_derived_type; + +#endif + } } diff --git a/boost/type_erasure/detail/access.hpp b/boost/type_erasure/detail/access.hpp index 4116bf1ceb..84c61931bb 100644 --- a/boost/type_erasure/detail/access.hpp +++ b/boost/type_erasure/detail/access.hpp @@ -14,6 +14,18 @@ #include <boost/type_erasure/detail/storage.hpp> #include <boost/type_erasure/detail/any_base.hpp> +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && \ + !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \ + !BOOST_WORKAROUND(BOOST_MSVC, == 1800) && \ + !BOOST_WORKAROUND(BOOST_GCC, < 40800) && /* Inherited constructors */ \ + !(defined(__clang_major__) && __clang_major__ == 3 && __clang__minor__ <= 2) /* Inherited constructors */ +#define BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS +#include <boost/type_traits/is_reference.hpp> +#include <boost/utility/enable_if.hpp> +#endif + namespace boost { namespace type_erasure { @@ -23,6 +35,9 @@ class any; template<class Concept, class T> class param; +template<class Concept> +class binding; + namespace detail { struct access @@ -34,11 +49,51 @@ struct access return static_cast<const Derived&>(arg).table; } template<class Concept, class T> - static const typename any<Concept, T>::table_type& + static const ::boost::type_erasure::binding<Concept>& table(const ::boost::type_erasure::param<Concept, T>& arg) { + return table(arg._impl); + } + template<class Concept, class T> + static const ::boost::type_erasure::binding<Concept>& + table(const ::boost::type_erasure::param<Concept, T&>& arg) + { + return arg._impl.table; + } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template<class Concept, class T> + static const ::boost::type_erasure::binding<Concept>& + table(const ::boost::type_erasure::param<Concept, T&&>& arg) + { return arg._impl.table; } +#endif +#ifdef BOOST_TYPE_ERASURE_SFINAE_FRIENDLY_CONSTRUCTORS + template<class Concept, class T, class = typename ::boost::enable_if_c<!::boost::is_reference<T>::value>::type> + static const typename any<Concept, T>::table_type& + table(const ::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T> >& arg) + { + return static_cast<const ::boost::type_erasure::any<Concept, T>&>(arg)._boost_type_erasure_table; + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T> >& arg) + { + return static_cast< ::boost::type_erasure::any<Concept, T>&>(arg)._boost_type_erasure_data; + } + template<class Concept, class T> + static const ::boost::type_erasure::detail::storage& + data(const ::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T> >& arg) + { + return static_cast<const ::boost::type_erasure::any<Concept, T>&>(arg)._boost_type_erasure_data; + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage&& + data(::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T> >&& arg) + { + return std::move(static_cast< ::boost::type_erasure::any<Concept, T>&&>(arg)._boost_type_erasure_data); + } +#endif template<class Derived> static ::boost::type_erasure::detail::storage& data(::boost::type_erasure::any_base<Derived>& arg) @@ -59,6 +114,12 @@ struct access } template<class Concept, class T> static ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T&> >& arg) + { + return const_cast< ::boost::type_erasure::detail::storage&>(static_cast< ::boost::type_erasure::any<Concept, T&>&>(arg).data); + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage& data(const ::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T&> >& arg) { return const_cast< ::boost::type_erasure::detail::storage&>(static_cast< const ::boost::type_erasure::any<Concept, T&>&>(arg).data); @@ -73,6 +134,12 @@ struct access static ::boost::type_erasure::detail::storage& data(::boost::type_erasure::param<Concept, T>& arg) { + return data(arg._impl); + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::param<Concept, T&>& arg) + { return arg._impl.data; } template<class Concept, class T> @@ -85,6 +152,12 @@ struct access static const ::boost::type_erasure::detail::storage& data(const ::boost::type_erasure::param<Concept, T>& arg) { + return data(arg._impl); + } + template<class Concept, class T> + static const ::boost::type_erasure::detail::storage& + data(const ::boost::type_erasure::param<Concept, T&>& arg) + { return arg._impl.data; } @@ -104,18 +177,48 @@ struct access } template<class Concept, class T> static ::boost::type_erasure::detail::storage&& + data(::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T&&> >&& arg) + { + return std::move(static_cast< ::boost::type_erasure::any<Concept, T&&>&>(arg).data); + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage&& data(const ::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T&&> >& arg) { return std::move(const_cast< ::boost::type_erasure::detail::storage&>(static_cast< const ::boost::type_erasure::any<Concept, T&&>&>(arg).data)); } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::any_base< ::boost::type_erasure::any<Concept, T&> >&& arg) + { + return std::move(static_cast< ::boost::type_erasure::any<Concept, T&>&>(arg).data); + } template<class Concept, class T> static ::boost::type_erasure::detail::storage&& data(::boost::type_erasure::param<Concept, T>&& arg) { + return std::move(data(arg._impl)); + } + template<class Concept, class T> + static ::boost::type_erasure::detail::storage&& + data(::boost::type_erasure::param<Concept, T&&>&& arg) + { return std::move(arg._impl.data); } template<class Concept, class T> + static ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::param<Concept, T&>&& arg) + { + return arg._impl.data; + } + template<class Concept, class T> + static const ::boost::type_erasure::detail::storage& + data(::boost::type_erasure::param<Concept, const T&>&& arg) + { + return arg._impl.data; + } + template<class Concept, class T> static ::boost::type_erasure::detail::storage&& data(::boost::type_erasure::param<Concept, T&&>& arg) { diff --git a/boost/type_erasure/detail/adapt_to_vtable.hpp b/boost/type_erasure/detail/adapt_to_vtable.hpp index e58ddc8599..f842dc3985 100644 --- a/boost/type_erasure/detail/adapt_to_vtable.hpp +++ b/boost/type_erasure/detail/adapt_to_vtable.hpp @@ -39,24 +39,9 @@ namespace detail { template<class T, class Out> struct get_placeholders; -template<class T, class Bindings> -struct rebind_placeholders; - -template<class T, class Bindings> -struct rebind_placeholders_in_argument; - template<class PrimitiveConcept, class Sig> struct vtable_adapter; -template<class PrimitiveConcept, class Sig, class Bindings> -struct rebind_placeholders<vtable_adapter<PrimitiveConcept, Sig>, Bindings> -{ - typedef vtable_adapter< - typename rebind_placeholders<PrimitiveConcept, Bindings>::type, - typename rebind_placeholders_in_argument<Sig, Bindings>::type - > type; -}; - template<class PrimitiveConcept, class Sig, class Out> struct get_placeholders<vtable_adapter<PrimitiveConcept, Sig>, Out> { @@ -308,11 +293,13 @@ struct vtable_adapter<PrimitiveConcept, R(BOOST_PP_ENUM_PARAMS(N, T))> typedef R (*type)(BOOST_PP_ENUM_PARAMS(N, T)); static R value(BOOST_PP_ENUM_BINARY_PARAMS(N, T, arg)) { +#if N > 0 typedef typename ::boost::function_traits< typename ::boost::type_erasure::detail::get_signature< PrimitiveConcept >::type > traits; +#endif return PrimitiveConcept::apply( BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_EXTRACT, ~)); } @@ -325,11 +312,13 @@ struct vtable_adapter<PrimitiveConcept, ::boost::type_erasure::detail::storage(B typedef ::boost::type_erasure::detail::storage (*type)(BOOST_PP_ENUM_PARAMS(N, T)); static ::boost::type_erasure::detail::storage value(BOOST_PP_ENUM_BINARY_PARAMS(N, T, arg)) { +#if N > 0 typedef typename ::boost::function_traits< typename ::boost::type_erasure::detail::get_signature< PrimitiveConcept >::type > traits; +#endif return ::boost::type_erasure::detail::storage( PrimitiveConcept::apply( BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_EXTRACT, ~))); diff --git a/boost/type_erasure/detail/any_base.hpp b/boost/type_erasure/detail/any_base.hpp index 0fa316c9ff..b7c4f8c050 100644 --- a/boost/type_erasure/detail/any_base.hpp +++ b/boost/type_erasure/detail/any_base.hpp @@ -19,7 +19,9 @@ struct any_base { typedef void _boost_type_erasure_is_any; typedef Derived _boost_type_erasure_derived_type; - void* _boost_type_erasure_deduce_constructor(...) { return 0; } + // volatile makes this a worse match than the default constructor + // for msvc-14.1, which can get confused otherwise. + void* _boost_type_erasure_deduce_constructor(...) const volatile { return 0; } void* _boost_type_erasure_deduce_assign(...) { return 0; } }; diff --git a/boost/type_erasure/detail/check_call.hpp b/boost/type_erasure/detail/check_call.hpp index adf36dbeaa..daa9931146 100644 --- a/boost/type_erasure/detail/check_call.hpp +++ b/boost/type_erasure/detail/check_call.hpp @@ -113,10 +113,53 @@ struct check_placeholder_arg : #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ ((defined(__GNUC__) && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))) || \ - defined(__MINGW32__) || defined(__MINGW64__)) + defined(__MINGW32__) || defined(__MINGW64__) || \ + BOOST_WORKAROUND(BOOST_MSVC, <= 1700)) #define BOOST_TYPE_ERASURE_BROKEN_RVALUE_IS_CONVERTIBLE #endif +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class P, class Arg> +using check_placeholder_arg_t = + typename ::boost::type_erasure::detail::check_placeholder_arg_impl< + P, + typename ::boost::type_erasure::detail::qualified_placeholder<Arg>::type + >::type; + +template<class T, class Arg> +using check_nonplaceholder_arg_t = typename ::boost::is_convertible<Arg, T>::type; + +template<class FormalArg, class ActualArg> +using check_arg_t = + ::boost::type_erasure::detail::eval_if< + ::boost::type_erasure::is_placeholder< + ::boost::remove_cv_t< + ::boost::remove_reference_t<FormalArg> + > + >::value, + ::boost::type_erasure::detail::check_placeholder_arg_t, + ::boost::type_erasure::detail::check_nonplaceholder_arg_t, + FormalArg, + ActualArg + >; + +// MSVC 14.1 ICE's if we use check_arg_t directly. +template<class FormalArg, class ActualArg> +struct check_arg +{ + typedef ::boost::type_erasure::detail::check_arg_t<FormalArg, ActualArg> type; +}; + +template<class R, class... T, class... U> +struct check_call<R(T...), void(U...)> { + typedef ::boost::mp11::mp_all< + typename ::boost::type_erasure::detail::check_arg<T, U>::type... + > type; +}; + +#else + template<class FormalArg, class ActualArg> struct check_arg { @@ -135,10 +178,37 @@ struct check_arg >::type type; }; +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + #define BOOST_PP_FILENAME_1 <boost/type_erasure/detail/check_call.hpp> #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY) #include BOOST_PP_ITERATE() +#else + +template<class... B> +struct and_; + +template<class T1, class... T> +struct and_<T1, T...> : boost::mpl::eval_if_c<T1::type::value, and_<T...>, boost::mpl::false_>::type {}; + +template<class T1> +struct and_<T1> : T1::type {}; + +template<> +struct and_<> : boost::mpl::true_ {}; + +template<class R, class... T, class... U> +struct check_call<R(T...), void(U...)> { + typedef typename ::boost::type_erasure::detail::and_< + ::boost::type_erasure::detail::check_arg<T, U>... + >::type type; +}; + +#endif + +#endif + } } } diff --git a/boost/type_erasure/detail/check_map.hpp b/boost/type_erasure/detail/check_map.hpp index a51c95deb0..d39b61fba2 100644 --- a/boost/type_erasure/detail/check_map.hpp +++ b/boost/type_erasure/detail/check_map.hpp @@ -37,8 +37,18 @@ struct is_deduced< ::boost::type_erasure::deduced<T> > : boost::mpl::true_ {}; // returns true if Map has a key for every non-deduced placeholder in Concept template<class Concept, class Map> struct check_map { +#ifndef BOOST_TYPE_ERASURE_USE_MP11 typedef typename normalize_concept<Concept>::basic basic_components; - + + typedef typename ::boost::mpl::fold< + basic_components, + ::boost::mpl::set0<>, + ::boost::type_erasure::detail::get_placeholders< + ::boost::mpl::_2, + ::boost::mpl::_1 + > + >::type placeholders; + // Every non-deduced placeholder referenced in this // map is indirectly deduced. typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< @@ -51,15 +61,6 @@ struct check_map { ::boost::mpl::second< ::boost::mpl::_2> > >::type indirect_deduced_placeholders; - - typedef typename ::boost::mpl::fold< - basic_components, - ::boost::mpl::set0<>, - ::boost::type_erasure::detail::get_placeholders< - ::boost::mpl::_2, - ::boost::mpl::_1 - > - >::type placeholders; typedef typename ::boost::is_same< typename ::boost::mpl::find_if< placeholders, @@ -73,6 +74,35 @@ struct check_map { >::type, typename ::boost::mpl::end<placeholders>::type >::type type; + +#else + typedef ::boost::type_erasure::detail::get_all_placeholders< + ::boost::type_erasure::detail::normalize_concept_t<Concept> + > placeholders; + + // Every non-deduced placeholder referenced in this + // map is indirectly deduced. + typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< + Concept>::type placeholder_subs; + typedef ::boost::mp11::mp_unique< + ::boost::mp11::mp_append< + ::boost::mp11::mp_transform< + ::boost::mp11::mp_first, + ::boost::type_erasure::detail::make_mp_list<Map> + >, + ::boost::mp11::mp_transform< + ::boost::mp11::mp_second, + ::boost::type_erasure::detail::make_mp_list<placeholder_subs> + > + > + > okay_placeholders; + template<class P> + using check_placeholder = ::boost::mpl::or_< + ::boost::type_erasure::detail::is_deduced<P>, + ::boost::mp11::mp_set_contains<okay_placeholders, P> + >; + typedef ::boost::mp11::mp_all_of<placeholders, check_placeholder> type; +#endif }; template<class Concept, class Map> diff --git a/boost/type_erasure/detail/dynamic_vtable.hpp b/boost/type_erasure/detail/dynamic_vtable.hpp index 9e014ed61b..959f2f3a32 100644 --- a/boost/type_erasure/detail/dynamic_vtable.hpp +++ b/boost/type_erasure/detail/dynamic_vtable.hpp @@ -32,9 +32,15 @@ namespace detail { #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) template<class P> -struct dynamic_binding_impl -{ +struct dynamic_binding_impl { const std::type_info * type; + dynamic_binding_impl() = default; + constexpr dynamic_binding_impl(const std::type_info * t) : type(t) {} +}; + +template<class T> +struct dynamic_binding_element { + typedef const std::type_info * type; }; template<class Table> @@ -50,12 +56,15 @@ struct append_to_key { template<class... P> struct dynamic_vtable : dynamic_binding_impl<P>... { dynamic_vtable() = default; - template<class... T> - constexpr dynamic_vtable(T* ...t) : dynamic_binding_impl<P>{t}... {} + constexpr dynamic_vtable(typename dynamic_binding_element<P>::type ...t) : dynamic_binding_impl<P>(t)... {} template<class F> typename F::type lookup(F*) const { key_type key; +#ifndef BOOST_TYPE_ERASURE_USE_MP11 typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mpl::set0<> >::type placeholders; +#else + typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mp11::mp_list<> >::type placeholders; +#endif typedef typename ::boost::mpl::fold< placeholders, ::boost::mpl::map0<>, @@ -71,8 +80,13 @@ struct dynamic_vtable : dynamic_binding_impl<P>... { } template<class Bindings, class Src> void convert_from(const Src& src) { +#ifndef BOOST_TYPE_ERASURE_USE_MP11 *this = dynamic_vtable( (&src.lookup((::boost::type_erasure::typeid_<typename ::boost::mpl::at<Bindings, P>::type>*)0)())...); +#else + *this = dynamic_vtable( + (&src.lookup((::boost::type_erasure::typeid_< ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<Bindings, P> > >*)0)())...); +#endif } }; diff --git a/boost/type_erasure/detail/extract_concept.hpp b/boost/type_erasure/detail/extract_concept.hpp index f519045d6c..0b1ce5d2fa 100644 --- a/boost/type_erasure/detail/extract_concept.hpp +++ b/boost/type_erasure/detail/extract_concept.hpp @@ -42,6 +42,33 @@ struct combine_concepts<void, T> { typedef T type; }; template<> struct combine_concepts<void, void> { typedef void type; }; +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class T, class U> +using combine_concepts_t = typename ::boost::type_erasure::detail::combine_concepts<T, U>::type; + +template<class T, class U> +using extract_concept_or_void = + ::boost::mp11::mp_eval_if_c< + !::boost::type_erasure::is_placeholder< + ::boost::remove_cv_t< + ::boost::remove_reference_t<T> + > + >::value, + void, + ::boost::type_erasure::concept_of_t, U + >; + +template<class L1, class L2> +using extract_concept_t = + ::boost::mp11::mp_fold< + ::boost::mp11::mp_transform< ::boost::type_erasure::detail::extract_concept_or_void, L1, L2>, + void, + ::boost::type_erasure::detail::combine_concepts_t + >; + +#else + template<class T, class U> struct maybe_extract_concept { @@ -56,7 +83,7 @@ struct maybe_extract_concept >::type type; }; -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template<class Args, class... U> struct extract_concept; @@ -82,7 +109,6 @@ struct extract_concept<void()> }; #else -//#endif #define BOOST_PP_FILENAME_1 <boost/type_erasure/detail/extract_concept.hpp> #define BOOST_PP_ITERATION_LIMITS (1, BOOST_TYPE_ERASURE_MAX_ARITY) @@ -90,6 +116,8 @@ struct extract_concept<void()> #endif +#endif + } } } diff --git a/boost/type_erasure/detail/get_placeholders.hpp b/boost/type_erasure/detail/get_placeholders.hpp index cdee16fc03..a17d2d445c 100644 --- a/boost/type_erasure/detail/get_placeholders.hpp +++ b/boost/type_erasure/detail/get_placeholders.hpp @@ -21,6 +21,7 @@ #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> +#include <boost/type_erasure/detail/meta.hpp> #include <boost/type_erasure/config.hpp> #include <boost/type_erasure/is_placeholder.hpp> @@ -28,6 +29,87 @@ namespace boost { namespace type_erasure { namespace detail { +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class T> +struct get_placeholders_in_argument_impl +{ + template<class Out> + using apply = ::boost::type_erasure::detail::eval_if< + ::boost::type_erasure::is_placeholder<T>::value, + ::boost::mp11::mp_set_push_back, + ::boost::type_erasure::detail::first, + Out, T + >; +}; + +template<class T> +struct get_placeholders_in_argument_impl<T&> +{ + template<class Out> + using apply = typename ::boost::type_erasure::detail::get_placeholders_in_argument_impl<T>::template apply<Out>; +}; + +template<class T> +struct get_placeholders_in_argument_impl<T&&> +{ + template<class Out> + using apply = typename ::boost::type_erasure::detail::get_placeholders_in_argument_impl<T>::template apply<Out>; +}; + +template<class T> +struct get_placeholders_in_argument_impl<const T> +{ + template<class Out> + using apply = typename ::boost::type_erasure::detail::get_placeholders_in_argument_impl<T>::template apply<Out>; +}; + +template<class Out, class T> +using get_placeholders_f = typename get_placeholders_in_argument_impl<T>::template apply<Out>; + +template<class Out, class... T> +using get_placeholders_impl = + ::boost::mp11::mp_fold< + ::boost::mp11::mp_list<T...>, + Out, + ::boost::type_erasure::detail::get_placeholders_f + >; + +template<class R, class... T> +struct get_placeholders_in_argument_impl<R(T...)> +{ + template<class Out> + using apply = ::boost::type_erasure::detail::get_placeholders_impl<Out, R, T...>; +}; + +template<class R, class C, class... T> +struct get_placeholders_in_argument_impl<R (C::*)(T...)> +{ + template<class Out> + using apply = ::boost::type_erasure::detail::get_placeholders_impl<Out, R, C, T...>; +}; + +template<class R, class C, class... T> +struct get_placeholders_in_argument_impl<R (C::*)(T...) const> +{ + template<class Out> + using apply = ::boost::type_erasure::detail::get_placeholders_impl<Out, R, C, T...>; +}; + +template<class T, class Out> +struct get_placeholders; + +template<template<class...> class F, class... T, class Out> +struct get_placeholders<F<T...>, Out> +{ + using type = ::boost::type_erasure::detail::get_placeholders_impl<Out, T...>; +}; + +template<class T, class Out> +using get_placeholders_t = typename ::boost::type_erasure::detail::get_placeholders<T, Out>::type; + +#else + template<class T, class Out> struct get_placeholders_in_argument { @@ -88,11 +170,19 @@ struct get_placeholders<T<U...>, Out> template<class R, class... T, class Out> struct get_placeholders_in_argument<R(T...), Out> { - typedef typename ::boost::type_erasure::detail::get_placeholders_in_argument< - R, - Out - >::type type0; - typedef typename get_placeholders_impl<type0, T...>::type type; + typedef typename get_placeholders_impl<Out, R, T...>::type type; +}; + +template<class R, class C, class... T, class Out> +struct get_placeholders_in_argument<R (C::*)(T...), Out> +{ + typedef typename get_placeholders_impl<Out, R, C, T...>::type type; +}; + +template<class R, class C, class... T, class Out> +struct get_placeholders_in_argument<R (C::*)(T...) const, Out> +{ + typedef typename get_placeholders_impl<Out, R, C, T...>::type type; }; #else @@ -103,6 +193,8 @@ struct get_placeholders_in_argument<R(T...), Out> #endif +#endif + } } } diff --git a/boost/type_erasure/detail/instantiate.hpp b/boost/type_erasure/detail/instantiate.hpp index 74f3d27f83..742aa02a9b 100644 --- a/boost/type_erasure/detail/instantiate.hpp +++ b/boost/type_erasure/detail/instantiate.hpp @@ -28,6 +28,62 @@ namespace boost { namespace type_erasure { namespace detail { +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class L> +struct make_instantiate_concept_impl; + +template<class T, T t> +struct instantiate_concept; + +template<class T> +using instantiate_concept_impl = instantiate_concept<decltype(&T::apply), &T::apply>; + +template<class... T> +struct make_instantiate_concept_impl< ::boost::mp11::mp_list<T...> > +{ + template<template<class> class F> + using apply = void(F<T>...); +}; + +template<class Map> +struct instantiate_concept_rebind_f +{ + template<class T> + using apply = + typename ::boost::type_erasure::detail::rebind_placeholders< + T, + Map + >::type; +}; + +template<class Concept, class Map> +using make_instantiate_concept = + ::boost::type_erasure::detail::make_instantiate_concept_impl< + ::boost::mp11::mp_transform< + ::boost::type_erasure::detail::instantiate_concept_rebind_f< + typename ::boost::type_erasure::detail::add_deductions< + ::boost::type_erasure::detail::make_mp_list<Map>, + typename ::boost::type_erasure::detail::get_placeholder_normalization_map< + Concept + >::type + >::type + >::template apply, + ::boost::type_erasure::detail::normalize_concept_t<Concept> + > + >; + +#define BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map) \ + ((void)(typename ::boost::type_erasure::detail::make_instantiate_concept<Concept, Map> \ + ::template apply< ::boost::type_erasure::detail::instantiate_concept_impl>*)0) + +#define BOOST_TYPE_ERASURE_INSTANTIATE1(Concept, P0, T0) \ + ((void)(typename ::boost::type_erasure::detail::make_instantiate_concept< \ + Concept, ::boost::mpl::map1< ::boost::mpl::pair<P0, T0> > > \ + ::template apply< ::boost::type_erasure::detail::instantiate_concept_impl>*)0) + +#else + template<int N> struct make_instantiate_concept_impl; @@ -56,6 +112,8 @@ struct make_instantiate_concept { #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_FUNCTIONS) #include BOOST_PP_ITERATE() +#endif + } } } @@ -72,6 +130,7 @@ struct make_instantiate_concept { struct BOOST_PP_CAT(instantiate_concept, N) { template<class Concept, class Map> static void apply(Concept *, Map *) { +#if N > 0 typedef typename ::boost::type_erasure::detail::normalize_concept< Concept>::type normalized; typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< @@ -88,6 +147,7 @@ struct BOOST_PP_CAT(instantiate_concept, N) { >::type > >::type concept_sequence; +#endif BOOST_PP_REPEAT(N, BOOST_TYPE_ERASURE_INSTANTIATE_IMPL, concept_sequence) } }; diff --git a/boost/type_erasure/detail/member11.hpp b/boost/type_erasure/detail/member11.hpp new file mode 100644 index 0000000000..7bc8eee6a9 --- /dev/null +++ b/boost/type_erasure/detail/member11.hpp @@ -0,0 +1,214 @@ +// Boost.TypeErasure library +// +// Copyright 2018 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$ + +#ifndef BOOST_TYPE_ERASURE_DETAIL_MEMBER11_HPP_INCLUDED +#define BOOST_TYPE_ERASURE_DETAIL_MEMBER11_HPP_INCLUDED + +#include <boost/config.hpp> + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \ + !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + !defined(BOOST_NO_CXX11_DECLTYPE) && \ + !BOOST_WORKAROUND(BOOST_MSVC, == 1800) + +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/punctuation/is_begin_parens.hpp> +#include <boost/vmd/is_empty.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_erasure/detail/const.hpp> +#include <boost/type_erasure/detail/macro.hpp> +#include <boost/type_erasure/rebind_any.hpp> +#include <boost/type_erasure/param.hpp> +#include <boost/type_erasure/is_placeholder.hpp> +#include <boost/type_erasure/call.hpp> + +namespace boost { +namespace type_erasure { +namespace detail { + +template<class P, template<class ...> class interface, class Sig, class Concept, class Base, class ID> +using choose_member_interface = typename ::boost::mpl::if_c< ::boost::is_reference<P>::value, + typename ::boost::mpl::if_c< ::boost::type_erasure::detail::is_non_const_ref<P>::value, + interface<Sig, Concept, Base, const ID>, + Base + >::type, + interface<Sig, Concept, Base, ID> +>::type; + + +struct dummy {}; + +template<class Sig> +struct choose_member_impl; + +template<class R, class C, class... T> +struct choose_member_impl<R (C::*)(T...) const> +{ + template<class P, template<class> class M, template<class,class> class S> + using apply = ::boost::mpl::vector1<S<R(T...), const P> >; +}; + +template<class R, class C, class... T> +struct choose_member_impl<R (C::*)(T...)> +{ + template<class P, template<class> class M, template<class,class> class S> + using apply = M<R(P&, T...)>; +}; + +template<class Sig, class P, template<class> class M, template<class, class> class Self> +using choose_member_impl_t = + typename ::boost::type_erasure::detail::choose_member_impl< + Sig (::boost::type_erasure::detail::dummy::*) + >::template apply<P, M, Self>; + +template<class Sig, class T, class ID> +struct member_interface_chooser +{ + template<class Base, template<class, class> class C, template<class...> class M> + using apply = Base; +}; + +template<class R, class T, class... A> +struct member_interface_chooser<R(A...), T, T> +{ + template<class Base, template<class, class> class C, template<class...> class M> + using apply = ::boost::type_erasure::detail::choose_member_interface< + ::boost::type_erasure::placeholder_of_t<Base>, + M, + R(A...), C<R(A...), T>, Base, T>; +}; + +template<class R, class T, class... A> +struct member_interface_chooser<R(A...), const T, T> +{ + template<class Base, template<class, class> class C, template<class...> class M> + using apply = M<R(A...), C<R(A...), const T>, Base, const T>; +}; + +template<class Sig, class T, template<class, class> class C, template<class...> class M> +struct member_choose_interface +{ + template<class Concept, class Base, class ID> + using apply = typename ::boost::type_erasure::detail::member_interface_chooser<Sig, T, ID>::template apply<Base, C, M>; +}; + +} +} +} + +#define BOOST_TYPE_ERASURE_MEMBER_I(concept_name, function_name) \ +template<class Sig, class T = ::boost::type_erasure::_self> \ +struct concept_name; \ + \ +namespace boost_type_erasure_impl { \ + \ +template<class Sig, class T> \ +using concept_name ## self = concept_name<Sig, T>; \ + \ +template<class Sig, class Concept, class Base, class ID, class Enable = void>\ +struct concept_name ## _member_interface; \ + \ +template<class R, class... A, class Concept, class Base, class ID, class V> \ +struct concept_name ## _member_interface<R(A...), Concept, Base, ID, V> : Base\ +{ \ + typedef void _boost_type_erasure_has_member ## function_name; \ + ::boost::type_erasure::rebind_any_t<Base, R> function_name(::boost::type_erasure::as_param_t<Base, A>... a)\ + { return ::boost::type_erasure::call(Concept(), *this, std::forward<A>(a)...); }\ +}; \ + \ +template<class R, class... A, class Concept, class Base, class ID> \ +struct concept_name ## _member_interface<R(A...), Concept, Base, ID, \ + typename Base::_boost_type_erasure_has_member ## function_name> : Base \ +{ \ + using Base::function_name; \ + ::boost::type_erasure::rebind_any_t<Base, R> function_name(::boost::type_erasure::as_param_t<Base, A>... a)\ + { return ::boost::type_erasure::call(Concept(), *this, std::forward<A>(a)...); }\ +}; \ + \ +template<class R, class... A, class Concept, class Base, class ID, class V> \ +struct concept_name ## _member_interface<R(A...), Concept, Base, const ID, V> : Base\ +{ \ + typedef void _boost_type_erasure_has_member ## function_name; \ + ::boost::type_erasure::rebind_any_t<Base, R> function_name(::boost::type_erasure::as_param_t<Base, A>... a) const\ + { return ::boost::type_erasure::call(Concept(), *this, std::forward<A>(a)...); }\ +}; \ + \ +template<class R, class... A, class Concept, class Base, class ID> \ +struct concept_name ## _member_interface<R(A...), Concept, Base, const ID, \ + typename Base::_boost_type_erasure_has_member ## function_name> : Base \ +{ \ + using Base::function_name; \ + ::boost::type_erasure::rebind_any_t<Base, R> function_name(::boost::type_erasure::as_param_t<Base, A>... a) const\ + { return ::boost::type_erasure::call(Concept(), *this, std::forward<A>(a)...); }\ +}; \ + \ +template<class Sig> \ +struct concept_name ## member; \ + \ +template<class R, class T0, class... T> \ +struct concept_name ## member<R(T0, T...)> { \ + static R apply(T0 t0, T... t) \ + { return t0.function_name(std::forward<T>(t)...); } \ +}; \ + \ +template<class T0, class... T> \ +struct concept_name ## member<void(T0, T...)> { \ + static void apply(T0 t0, T... t) \ + { t0.function_name(std::forward<T>(t)...); } \ +}; \ + \ +} \ + \ +template<class Sig, class T> \ +struct concept_name : \ + ::boost::type_erasure::detail::choose_member_impl_t<Sig, T, \ + boost_type_erasure_impl::concept_name##member, \ + boost_type_erasure_impl::concept_name##self \ + > \ +{}; \ + \ +template<class Sig, class T> \ +::boost::type_erasure::detail::member_choose_interface<Sig, T, concept_name,\ + boost_type_erasure_impl::concept_name ## _member_interface> \ +boost_type_erasure_find_interface(concept_name<Sig, T>); + +#define BOOST_TYPE_ERASURE_MEMBER_SIMPLE(name, ...) \ + BOOST_TYPE_ERASURE_MEMBER_I(has_ ## name, name) + +#define BOOST_TYPE_ERASURE_MEMBER_NS_I(concept_name, name) \ + BOOST_TYPE_ERASURE_MEMBER_I(concept_name, name) + +#define BOOST_TYPE_ERASURE_MEMBER_NS(concept_name, name) \ + BOOST_TYPE_ERASURE_OPEN_NAMESPACE(concept_name) \ + BOOST_TYPE_ERASURE_MEMBER_NS_I(BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(concept_name)), concept_name), name) \ + BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(concept_name) + +#define BOOST_TYPE_ERASURE_MEMBER_NAMED(concept_name, name, ...) \ + BOOST_PP_IF(BOOST_PP_IS_BEGIN_PARENS(concept_name), \ + BOOST_TYPE_ERASURE_MEMBER_NS, \ + BOOST_TYPE_ERASURE_MEMBER_I) \ + (concept_name, name) + +#define BOOST_TYPE_ERASURE_MEMBER_CAT(x, y) x y + +#define BOOST_TYPE_ERASURE_MEMBER(name, ...) \ + BOOST_TYPE_ERASURE_MEMBER_CAT( \ + BOOST_PP_IF(BOOST_VMD_IS_EMPTY(__VA_ARGS__), \ + BOOST_TYPE_ERASURE_MEMBER_SIMPLE, \ + BOOST_TYPE_ERASURE_MEMBER_NAMED), \ + (name, __VA_ARGS__)) + +#endif + +#endif diff --git a/boost/type_erasure/detail/meta.hpp b/boost/type_erasure/detail/meta.hpp new file mode 100644 index 0000000000..96e786fde6 --- /dev/null +++ b/boost/type_erasure/detail/meta.hpp @@ -0,0 +1,89 @@ +// Boost.TypeErasure library +// +// Copyright 2018 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$ + +#ifndef BOOST_TYPE_ERASURE_DETAIL_META_HPP_INCLUDED +#define BOOST_TYPE_ERASURE_DETAIL_META_HPP_INCLUDED + +#include <boost/config.hpp> + + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \ + /* MSVC 14.0 breaks down in the template alias quagmire. */ \ + !BOOST_WORKAROUND(BOOST_MSVC, <= 1900) + +#define BOOST_TYPE_ERASURE_USE_MP11 + +#include <boost/mp11/list.hpp> +#include <boost/mp11/map.hpp> +#include <boost/mp11/set.hpp> +#include <boost/mp11/algorithm.hpp> +#include <boost/mp11/function.hpp> +#include <boost/mp11/mpl.hpp> + +namespace boost { +namespace type_erasure { +namespace detail { + +struct mp11_list_inserter +{ + template<class L, class T> + using apply = ::boost::mpl::identity< ::boost::mp11::mp_push_back<L, T> >; +}; + +template<class T> +struct make_mp_list_impl +{ + typedef typename ::boost::mpl::fold< + T, + ::boost::mp11::mp_list<>, + ::boost::type_erasure::detail::mp11_list_inserter + >::type type; +}; + +template<class... T> +struct make_mp_list_impl< ::boost::mp11::mp_list<T...> > +{ + typedef ::boost::mp11::mp_list<T...> type; +}; + +template<class T> +using make_mp_list = typename make_mp_list_impl<T>::type; + +template<bool> +struct eval_if_impl; + +template<> +struct eval_if_impl<true> +{ + template<template<class...> class T, template<class...> class F, class... A> + using apply = T<A...>; +}; + +template<> +struct eval_if_impl<false> +{ + template<template<class...> class T, template<class...> class F, class... A> + using apply = F<A...>; +}; + +template<bool B, template<class...> class T, template<class...> class F, class... A> +using eval_if = typename ::boost::type_erasure::detail::eval_if_impl<B>::template apply<T, F, A...>; + +template<class T0, class...> +using first = T0; + +} +} +} + +#endif + +#endif diff --git a/boost/type_erasure/detail/normalize.hpp b/boost/type_erasure/detail/normalize.hpp index a6849a6cd9..02c232a612 100644 --- a/boost/type_erasure/detail/normalize.hpp +++ b/boost/type_erasure/detail/normalize.hpp @@ -30,6 +30,7 @@ #include <boost/type_erasure/detail/get_placeholders.hpp> #include <boost/type_erasure/detail/rebind_placeholders.hpp> #include <boost/type_erasure/detail/normalize_deduced.hpp> +#include <boost/type_erasure/detail/meta.hpp> #include <boost/type_erasure/relaxed.hpp> #include <boost/type_erasure/builtin.hpp> @@ -43,7 +44,6 @@ template<class T, class U> struct same_type; namespace detail { - struct substitution_map_tag {}; // a wrapper around an mpl::map that @@ -87,20 +87,6 @@ struct has_key_impl< ::boost::type_erasure::detail::substitution_map_tag> namespace type_erasure { namespace detail { -// given a partial substitution map from same_type, -// resolves a placeholder as far as possible. -template<class M, class T> -struct resolve_same_type -{ - typedef typename ::boost::mpl::eval_if< ::boost::mpl::has_key<M, T>, - ::boost::type_erasure::detail::resolve_same_type< - M, - typename ::boost::mpl::at<M, T>::type - >, - ::boost::mpl::identity<T> - >::type type; -}; - // Given the arguments to same_type, determines // which should be the key and which should be // the value in the substitution map. @@ -135,6 +121,22 @@ struct select_pair< > type; }; +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + +// given a partial substitution map from same_type, +// resolves a placeholder as far as possible. +template<class M, class T> +struct resolve_same_type +{ + typedef typename ::boost::mpl::eval_if< ::boost::mpl::has_key<M, T>, + ::boost::type_erasure::detail::resolve_same_type< + M, + typename ::boost::mpl::at<M, T>::type + >, + ::boost::mpl::identity<T> + >::type type; +}; + // M is a map of placeholder substitutions template<class M, class T> struct normalize_placeholder @@ -377,20 +379,422 @@ struct collect_concepts Concept, ::boost::type_erasure::detail::substitution_map<Map> >::type transformed; + typedef typename ::boost::mpl::eval_if< ::boost::mpl::is_sequence<Concept>, + ::boost::mpl::fold<Concept, Out, collect_concepts< ::boost::mpl::_2, Map, ::boost::mpl::_1> >, + ::boost::mpl::identity<Out> + >::type type1; typedef typename ::boost::mpl::eval_if< ::boost::is_same<transformed, void>, - ::boost::mpl::identity<Out>, + ::boost::mpl::identity<type1>, ::boost::mpl::insert< - Out, + type1, transformed > - >::type type1; - typedef typename ::boost::mpl::eval_if< ::boost::mpl::is_sequence<Concept>, - ::boost::mpl::fold<Concept, type1, collect_concepts< ::boost::mpl::_2, Map, ::boost::mpl::_1> >, - ::boost::mpl::identity<type1> >::type type; }; +#else + +template<bool> +struct resolve_same_type_impl; + +template<class M, class T> +using resolve_same_type_t = + typename ::boost::type_erasure::detail::resolve_same_type_impl< + (::boost::mp11::mp_map_contains<M, T>::value) + >::template apply<M, T>; + +template<> +struct resolve_same_type_impl<true> +{ + template<class M, class T> + using apply = ::boost::type_erasure::detail::resolve_same_type_t< + M, + ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<M, T> > + >; +}; + +template<> +struct resolve_same_type_impl<false> +{ + template<class M, class T> + using apply = T; +}; + +// given a partial substitution map from same_type, +// resolves a placeholder as far as possible. +template<class M, class T> +using resolve_same_type = ::boost::mpl::identity< ::boost::type_erasure::detail::resolve_same_type_t<M, T> >; + + +// M is a map of placeholder substitutions + +template<bool> +struct normalize_placeholder_impl; + +template<class M, class T> +using normalize_placeholder_t = + typename ::boost::type_erasure::detail::normalize_placeholder_impl< + ::boost::mp11::mp_map_contains<M, T>::value + >::template apply<M, T>; + +template<> +struct normalize_placeholder_impl<true> +{ + template<class M, class T> + using apply = ::boost::type_erasure::detail::normalize_placeholder_t< + M, + typename ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<M, T> > + >; +}; + +template<class T> +struct normalize_deduced_impl +{ + template<class Map> + using apply = T; +}; + +template<template<class...> class F, class... T> +struct normalize_deduced_impl< ::boost::type_erasure::deduced<F<T...> > > +{ + template<class Map> + using apply = typename ::boost::type_erasure::deduced<F<normalize_placeholder_t<Map, T>...> >::type; +}; + +template<> +struct normalize_placeholder_impl<false> +{ + template<class M, class T> + using apply = typename ::boost::type_erasure::detail::normalize_deduced_impl<T>::template apply<M>; +}; + +template<class Map, class T> +using normalize_placeholder = ::boost::mpl::identity< ::boost::type_erasure::detail::normalize_placeholder_t<Map, T> >; + +// Takes a mpl::map of placeholder substitutions and +// fully resolves it. i.e. a -> b, b -> c, becomes +// a -> c, b -> c. Also resolves deduced placeholders +// whose arguments are all resolved. +template<class M> +struct create_placeholder_map +{ + template<class P> + using transform_one = ::boost::mpl::pair< + typename ::boost::mpl::first<P>::type, + ::boost::type_erasure::detail::normalize_placeholder_t< + M, + typename ::boost::mpl::second<P>::type + > + >; + typedef ::boost::mp11::mp_transform< + transform_one, + M + > type; +}; + +template<class M> +using create_placeholder_map_t = typename ::boost::type_erasure::detail::create_placeholder_map<M>::type; + +template<class Bindings, class P, class Out, class Sub> +struct convert_deduced +{ + typedef ::boost::type_erasure::detail::rebind_placeholders_in_argument_t< + typename P::first, + Bindings + > result1; + typedef ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<Sub, result1> > result; + typedef ::boost::mp11::mp_map_insert<Out, ::boost::mpl::pair<typename P::second, result> > type; + BOOST_MPL_ASSERT((boost::is_same< ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<type, typename P::second> >, result>)); +}; + +template<class Bindings, class Sub> +struct convert_deduced_f +{ + template<class Out, class P> + using apply = typename ::boost::type_erasure::detail::convert_deduced<Bindings, P, Out, Sub>::type; +}; + +template<class Bindings, class M, class Sub> +using convert_deductions_t = + ::boost::mp11::mp_fold< + M, + ::boost::type_erasure::detail::make_mp_list<Bindings>, + ::boost::type_erasure::detail::convert_deduced_f<Bindings, Sub>::template apply + >; + +template<class Bindings, class M, class Sub> +using convert_deductions = ::boost::mpl::identity< ::boost::type_erasure::detail::convert_deductions_t<Bindings, M, Sub> >; + +template<class Bindings, class P, class Out> +struct add_deduced +{ + typedef typename ::boost::type_erasure::detail::rebind_placeholders_in_argument< + typename P::first, + Bindings + >::type result; + typedef ::boost::mp11::mp_map_insert<Out, ::boost::mpl::pair<typename P::second, result> > type; + BOOST_MPL_ASSERT((boost::is_same< ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<type, typename P::second> >, result>)); +}; + +template<class Bindings> +struct add_deduced_f +{ + template<class Out, class P> + using apply = typename ::boost::type_erasure::detail::add_deduced<Bindings, P, Out>::type; +}; + +template<class Bindings, class M> +using add_deductions_t = + ::boost::mp11::mp_fold< + M, + ::boost::type_erasure::detail::make_mp_list<Bindings>, + ::boost::type_erasure::detail::add_deduced_f< + ::boost::type_erasure::detail::make_mp_list<Bindings> + >::template apply + >; + +template<class Bindings, class M> +using add_deductions = ::boost::mpl::identity< ::boost::type_erasure::detail::add_deductions_t<Bindings, M> >; + +// Fold Op for normalize_concept_impl +template<class T> +struct insert_concept_impl +{ + template<class Out> + using apply = + ::boost::mpl::pair< + ::boost::mp11::mp_set_push_back<typename Out::first, T>, + typename Out::second + >; +}; + +template<class Map, class T> +using mpl_insert = typename ::boost::mpl::insert<Map, T>::type; + +template<class T1, class T2, class Out> +using insert_concept_same_type = + ::boost::mpl::pair< + typename Out::first, + typename ::boost::type_erasure::detail::eval_if< + ::boost::is_same<T1, T2>::value, + ::boost::type_erasure::detail::first, + ::boost::mp11::mp_map_insert, // FIXME: is this supposed to be a replace? + typename Out::second, + typename ::boost::type_erasure::detail::select_pair< + T1, + T2 + >::type + > + >; + +template<class T, class U> +struct insert_concept_impl< ::boost::type_erasure::same_type<T, U> > +{ + template<class Out> + using apply = ::boost::type_erasure::detail::insert_concept_same_type< + ::boost::type_erasure::detail::resolve_same_type_t< + typename Out::second, + T + >, + ::boost::type_erasure::detail::resolve_same_type_t< + typename Out::second, + U + >, + Out + >; +}; + +template<bool> +struct normalize_concept_impl_test; + +template<class Out, class Concept> +using normalize_concept_impl_f = + typename ::boost::type_erasure::detail::normalize_concept_impl_test< + ::boost::mpl::is_sequence<Concept>::value + >::template apply<Out, Concept>; + +template<> +struct normalize_concept_impl_test<true> +{ + template<class Out, class Concept> + using apply = + ::boost::mp11::mp_fold< + ::boost::type_erasure::detail::make_mp_list<Concept>, + Out, + ::boost::type_erasure::detail::normalize_concept_impl_f + >; +}; + +template<> +struct normalize_concept_impl_test<false> +{ + template<class Out, class Concept> + using apply = typename ::boost::type_erasure::detail::insert_concept_impl<Concept>::template apply<Out>; +}; + +template<class Concept> +using normalize_concept_impl_t = + ::boost::type_erasure::detail::normalize_concept_impl_f< + ::boost::mpl::pair< ::boost::mp11::mp_list<>, ::boost::mp11::mp_list<> >, + Concept + >; + +template<class Concept> +using normalize_concept_impl = ::boost::mpl::identity< ::boost::type_erasure::detail::normalize_concept_impl_t<Concept> >; + +template<class S, class T> +using get_all_placeholders_impl = typename ::boost::type_erasure::detail::get_placeholders<T, S>::type; + +template<class Seq> +using get_all_placeholders = + ::boost::mp11::mp_fold< + Seq, + ::boost::mp11::mp_list<>, + ::boost::type_erasure::detail::get_all_placeholders_impl + >; + +template<class T> +using make_identity_pair = ::boost::mpl::pair<T, T>; + +template<class Concept> +using make_identity_placeholder_map = + ::boost::mp11::mp_transform< + ::boost::type_erasure::detail::make_identity_pair, + ::boost::type_erasure::detail::get_all_placeholders< + typename normalize_concept_impl_t<Concept>::first + > + >; + +template<class S, class T> +using append_type_info = ::boost::mp11::mp_set_push_back< + S, + ::boost::type_erasure::typeid_<T> +>; + +template<class Seq> +using add_typeinfo_t = + ::boost::mp11::mp_fold< + get_all_placeholders<Seq>, + Seq, + ::boost::type_erasure::detail::append_type_info + >; + +// Seq should be a flattened mp_list sequence of leaf concepts. +// adds typeid_<P> for every placeholder used. +template<class Seq> +using add_typeinfo = ::boost::mpl::identity<add_typeinfo_t<Seq> >; + +template<class Substitutions> +struct normalize_concept_substitute_f +{ + template<class Set, class Concept> + using apply = ::boost::mp11::mp_set_push_back<Set, + typename ::boost::type_erasure::detail::rebind_placeholders< + Concept, + Substitutions + >::type + >; +}; + +template<class Concept, class Pair> +using normalize_concept_adjustments = + ::boost::type_erasure::detail::eval_if< + ::boost::type_erasure::is_relaxed<Concept>::value, + ::boost::type_erasure::detail::add_typeinfo_t, + ::boost::type_erasure::detail::first, + ::boost::mp11::mp_fold< + typename Pair::first, + ::boost::mp11::mp_list<>, + ::boost::type_erasure::detail::normalize_concept_substitute_f< + ::boost::type_erasure::detail::create_placeholder_map_t< + typename Pair::second + > + >::template apply + > + >; + +template<class Concept> +using get_placeholder_normalization_map_t = + ::boost::type_erasure::detail::create_placeholder_map_t< + typename normalize_concept_impl_t<Concept>::second + >; + +template<class Concept> +using get_placeholder_normalization_map = + ::boost::type_erasure::detail::create_placeholder_map< + typename normalize_concept_impl_t<Concept>::second + >; + +// Flattens a Concept to an mpl::vector of primitive +// concepts. Resolves same_type and deduced placeholders. +template<class Concept> +using normalize_concept_t = + ::boost::type_erasure::detail::normalize_concept_adjustments< + Concept, + boost::type_erasure::detail::normalize_concept_impl_t<Concept> + >; + +template<class Concept> +using normalize_concept = ::boost::mpl::identity< ::boost::type_erasure::detail::normalize_concept_t<Concept> >; + +template<class Map> +struct collect_concepts_f; + +template<class Out, class Concept, class Map> +using collect_concepts_recursive = ::boost::mp11::mp_fold< + ::boost::type_erasure::detail::make_mp_list<Concept>, + Out, + ::boost::type_erasure::detail::collect_concepts_f<Map>::template apply +>; + +template<class Concept, class Map, class Out, class Transformed> +using collect_concepts_impl = + ::boost::type_erasure::detail::eval_if< ::boost::is_same<Transformed, void>::value, + ::boost::type_erasure::detail::first, + ::boost::mp11::mp_set_push_front, + ::boost::type_erasure::detail::eval_if< ::boost::mpl::is_sequence<Concept>::value, + ::boost::type_erasure::detail::collect_concepts_recursive, + ::boost::type_erasure::detail::first, + Out, + Concept, + Map + >, + Transformed + >; + +template<class Concept, + class Map = ::boost::type_erasure::detail::create_placeholder_map_t< + typename ::boost::type_erasure::detail::normalize_concept_impl_t< + Concept + >::second + >, + class Out = ::boost::mp11::mp_list<> +> +using collect_concepts_t = + collect_concepts_impl<Concept, Map, Out, + typename ::boost::type_erasure::detail::rebind_placeholders< + Concept, + Map + >::type + >; + +template<class Map> +struct collect_concepts_f +{ + template<class Out, class Concept> + using apply = ::boost::type_erasure::detail::collect_concepts_t<Concept, Map, Out>; +}; + +// Returns an MPL sequence containing all the concepts +// in Concept. If Concept is considered as a DAG, +// the result will be sorted topologically. +template<class Concept> +using collect_concepts = ::boost::mpl::identity< + ::boost::type_erasure::detail::collect_concepts_t<Concept> >; + +#endif + } } } diff --git a/boost/type_erasure/detail/normalize_deduced.hpp b/boost/type_erasure/detail/normalize_deduced.hpp index 83d0d3b25b..dcf3fd3625 100644 --- a/boost/type_erasure/detail/normalize_deduced.hpp +++ b/boost/type_erasure/detail/normalize_deduced.hpp @@ -16,6 +16,9 @@ #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> +#include <boost/type_erasure/detail/meta.hpp> + +#ifndef BOOST_TYPE_ERASURE_USE_MP11 namespace boost { namespace type_erasure { @@ -36,6 +39,8 @@ struct normalize_placeholder; #endif +#endif + #else #define N BOOST_PP_ITERATION() diff --git a/boost/type_erasure/detail/null.hpp b/boost/type_erasure/detail/null.hpp index ef977f4254..e0c3173704 100644 --- a/boost/type_erasure/detail/null.hpp +++ b/boost/type_erasure/detail/null.hpp @@ -13,6 +13,7 @@ #ifndef BOOST_TYPE_ERASURE_DETAIL_NULL_HPP_INCLUDED #define BOOST_TYPE_ERASURE_DETAIL_NULL_HPP_INCLUDED +#include <boost/config.hpp> #include <boost/throw_exception.hpp> #include <boost/type_traits/remove_pointer.hpp> #include <boost/preprocessor/iteration/iterate.hpp> @@ -34,10 +35,23 @@ struct get_null_vtable_entry { typename ::boost::remove_pointer<typename Concept::type>::type> type; }; +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + #define BOOST_PP_FILENAME_1 <boost/type_erasure/detail/null.hpp> #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY) #include BOOST_PP_ITERATE() +#else + +template<class R, class... T> +struct null_throw<R(T...)> { + static R value(T...) { + BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_function_call()); + } +}; + +#endif + } } } diff --git a/boost/type_erasure/detail/rebind_placeholders.hpp b/boost/type_erasure/detail/rebind_placeholders.hpp index d93d429c5d..0d0ef7c8e4 100644 --- a/boost/type_erasure/detail/rebind_placeholders.hpp +++ b/boost/type_erasure/detail/rebind_placeholders.hpp @@ -26,6 +26,7 @@ #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> #include <boost/type_erasure/config.hpp> +#include <boost/type_erasure/detail/meta.hpp> #include <boost/type_erasure/is_placeholder.hpp> namespace boost { @@ -48,6 +49,132 @@ struct identity typedef T type; }; +template<class PrimitiveConcept, class Sig> +struct vtable_adapter; + +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class T, class Bindings> +using rebind_placeholders_t = typename rebind_placeholders<T, Bindings>::type; + +template<class T, class Bindings> +using rebind_one_placeholder = ::boost::mp11::mp_second< ::boost::mp11::mp_map_find<Bindings, T> >; + +template<class T> +struct rebind_placeholders_in_argument_impl +{ + template<class Bindings> + using apply = ::boost::type_erasure::detail::eval_if< + ::boost::mp11::mp_map_contains<Bindings, T>::value, + ::boost::type_erasure::detail::rebind_one_placeholder, + ::boost::type_erasure::detail::first, + T, + Bindings + >; +}; + +template<class T, class Bindings> +using rebind_placeholders_in_argument_t = typename ::boost::type_erasure::detail::rebind_placeholders_in_argument_impl<T>::template apply<Bindings>; + +template<class T, class Bindings> +using rebind_placeholders_in_argument = ::boost::mpl::identity< ::boost::type_erasure::detail::rebind_placeholders_in_argument_t<T, Bindings> >; + +template<class T> +struct rebind_placeholders_in_argument_impl<T&> +{ + template<class Bindings> + using apply = rebind_placeholders_in_argument_t<T, Bindings>&; +}; + +template<class T> +struct rebind_placeholders_in_argument_impl<T&&> +{ + template<class Bindings> + using apply = rebind_placeholders_in_argument_t<T, Bindings>&&; +}; + +template<class T> +struct rebind_placeholders_in_argument_impl<const T> +{ + template<class Bindings> + using apply = rebind_placeholders_in_argument_t<T, Bindings> const; +}; + +template<class F, class Bindings> +using rebind_placeholders_in_deduced = + typename ::boost::type_erasure::deduced< + ::boost::type_erasure::detail::rebind_placeholders_t<F, Bindings> + >::type; + +template<class F, class Bindings> +using rebind_deduced_placeholder = + ::boost::mp11::mp_second< + ::boost::mp11::mp_map_find<Bindings, ::boost::type_erasure::deduced<F> > + >; + +template<class F> +struct rebind_placeholders_in_argument_impl< + ::boost::type_erasure::deduced<F> +> +{ + template<class Bindings> + using apply = ::boost::type_erasure::detail::eval_if< + ::boost::mp11::mp_map_contains<Bindings, ::boost::type_erasure::deduced<F> >::value, + ::boost::type_erasure::detail::rebind_deduced_placeholder, + ::boost::type_erasure::detail::rebind_placeholders_in_deduced, + F, + Bindings + >; +}; + +template<class R, class... T> +struct rebind_placeholders_in_argument_impl<R(T...)> +{ + template<class Bindings> + using apply = + rebind_placeholders_in_argument_t<R, Bindings> + (rebind_placeholders_in_argument_t<T, Bindings>...); +}; + +template<class R, class C, class... T> +struct rebind_placeholders_in_argument_impl<R (C::*)(T...)> +{ + template<class Bindings> + using apply = + rebind_placeholders_in_argument_t<R, Bindings> + (rebind_placeholders_in_argument_t<C, Bindings>::*) + (rebind_placeholders_in_argument_t<T, Bindings>...); +}; + +template<class R, class C, class... T> +struct rebind_placeholders_in_argument_impl<R (C::*)(T...) const> +{ + template<class Bindings> + using apply = + rebind_placeholders_in_argument_t<R, Bindings> + (rebind_placeholders_in_argument_t<C, Bindings>::*) + (rebind_placeholders_in_argument_t<T, Bindings>...) const; +}; + +template<template<class...> class T, class... U, class Bindings> +struct rebind_placeholders<T<U...>, Bindings> +{ + typedef ::boost::type_erasure::detail::make_mp_list<Bindings> xBindings; + typedef T<rebind_placeholders_in_argument_t<U, xBindings>...> type; +}; + +template<class PrimitiveConcept, class Sig, class Bindings> +struct rebind_placeholders<vtable_adapter<PrimitiveConcept, Sig>, Bindings> +{ + typedef ::boost::type_erasure::detail::make_mp_list<Bindings> xBindings; + typedef vtable_adapter< + rebind_placeholders_t<PrimitiveConcept, xBindings>, + rebind_placeholders_in_argument_t<Sig, xBindings> + > type; +}; + +#else + template<class T, class Bindings> struct rebind_placeholders_in_argument { @@ -62,6 +189,15 @@ struct rebind_placeholders_in_argument >::type type; }; +template<class PrimitiveConcept, class Sig, class Bindings> +struct rebind_placeholders<vtable_adapter<PrimitiveConcept, Sig>, Bindings> +{ + typedef vtable_adapter< + typename rebind_placeholders<PrimitiveConcept, Bindings>::type, + typename rebind_placeholders_in_argument<Sig, Bindings>::type + > type; +}; + template<class T, class Bindings> struct rebind_placeholders_in_argument<T&, Bindings> { @@ -134,6 +270,26 @@ struct rebind_placeholders_in_argument<R(T...), Bindings> >::type type(typename rebind_placeholders_in_argument<T, Bindings>::type...); }; +template<class R, class C, class... T, class Bindings> +struct rebind_placeholders_in_argument<R (C::*)(T...), Bindings> +{ + typedef typename ::boost::type_erasure::detail::rebind_placeholders_in_argument< + R, + Bindings + >::type (rebind_placeholders_in_argument<C, Bindings>::type::*type) + (typename rebind_placeholders_in_argument<T, Bindings>::type...); +}; + +template<class R, class C, class... T, class Bindings> +struct rebind_placeholders_in_argument<R (C::*)(T...) const, Bindings> +{ + typedef typename ::boost::type_erasure::detail::rebind_placeholders_in_argument< + R, + Bindings + >::type (rebind_placeholders_in_argument<C, Bindings>::type::*type) + (typename rebind_placeholders_in_argument<T, Bindings>::type...) const; +}; + #else #define BOOST_PP_FILENAME_1 <boost/type_erasure/detail/rebind_placeholders.hpp> @@ -142,6 +298,8 @@ struct rebind_placeholders_in_argument<R(T...), Bindings> #endif +#endif + } } } diff --git a/boost/type_erasure/detail/storage.hpp b/boost/type_erasure/detail/storage.hpp index 8f8bf865ea..8e572871f3 100644 --- a/boost/type_erasure/detail/storage.hpp +++ b/boost/type_erasure/detail/storage.hpp @@ -13,7 +13,7 @@ #include <boost/config.hpp> #include <boost/type_traits/remove_reference.hpp> -#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/decay.hpp> #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES # include <utility> // for std::forward, std::move @@ -37,11 +37,10 @@ struct storage storage(storage&& other) : data(other.data) {} storage& operator=(const storage& other) { data = other.data; return *this; } template<class T> - explicit storage(T&& arg) : data(new typename remove_cv< - typename remove_reference<T>::type>::type(std::forward<T>(arg))) {} + explicit storage(T&& arg) : data(new typename boost::decay<T>::type(std::forward<T>(arg))) {} #else template<class T> - explicit storage(const T& arg) : data(new T(arg)) {} + explicit storage(const T& arg) : data(new typename boost::decay<T>::type(arg)) {} #endif void* data; }; diff --git a/boost/type_erasure/detail/vtable.hpp b/boost/type_erasure/detail/vtable.hpp index b30a15a061..965ffcb390 100644 --- a/boost/type_erasure/detail/vtable.hpp +++ b/boost/type_erasure/detail/vtable.hpp @@ -17,6 +17,7 @@ #include <boost/mpl/at.hpp> #include <boost/mpl/size.hpp> #include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/expr_if.hpp> #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> @@ -98,7 +99,7 @@ struct compare_vtable; template<> struct compare_vtable<> { template<class S> - static bool apply(const S& s1, const S& s2) + static bool apply(const S& /*s1*/, const S& /*s2*/) { return true; } @@ -151,9 +152,9 @@ struct vtable_storage<> vtable_storage() = default; template<class Bindings, class Src> - void convert_from(const Src& src) {} + void convert_from(const Src& /*src*/) {} - bool operator==(const vtable_storage& other) const + bool operator==(const vtable_storage& /*other*/) const { return true; } }; @@ -249,12 +250,12 @@ struct BOOST_PP_CAT(vtable_storage, N) BOOST_PP_REPEAT(N, BOOST_TYPE_ERASURE_VTABLE_ENTRY, ~) template<class Bindings, class Src> - void convert_from(const Src& src) + void convert_from(const Src& BOOST_PP_EXPR_IF(N, src)) { BOOST_PP_REPEAT(N, BOOST_TYPE_ERASURE_CONVERT_ELEMENT, ~) } - bool operator==(const BOOST_PP_CAT(vtable_storage, N)& other) const + bool operator==(const BOOST_PP_CAT(vtable_storage, N)& BOOST_PP_EXPR_IF(N, other)) const { return true BOOST_PP_REPEAT(N, BOOST_TYPE_ERASURE_VTABLE_COMPARE, ~); } }; diff --git a/boost/type_erasure/dynamic_any_cast.hpp b/boost/type_erasure/dynamic_any_cast.hpp index 01aa2b6ef9..6f0939e00d 100644 --- a/boost/type_erasure/dynamic_any_cast.hpp +++ b/boost/type_erasure/dynamic_any_cast.hpp @@ -96,13 +96,21 @@ R dynamic_any_cast_impl(Any& arg, const static_binding<Map>& map) >::type normalized; typedef typename ::boost::mpl::fold< normalized, +#ifndef BOOST_TYPE_ERASURE_USE_MP11 ::boost::mpl::set0<>, +#else + ::boost::mp11::mp_list<>, +#endif ::boost::type_erasure::detail::get_placeholders< ::boost::mpl::_2, ::boost::mpl::_1 > >::type placeholders; +#ifndef BOOST_TYPE_ERASURE_USE_MP11 typedef ::boost::type_erasure::detail::substitution_map< ::boost::mpl::map0<> > identity_map; +#else + typedef ::boost::type_erasure::detail::make_identity_placeholder_map<normalized> identity_map; +#endif ::boost::type_erasure::dynamic_binding<placeholders> my_binding( ::boost::type_erasure::binding_of(arg), ::boost::type_erasure::make_binding<identity_map>()); @@ -153,7 +161,7 @@ R dynamic_any_cast_impl(Any& arg, const static_binding<Map>& map) * * \throws bad_any_cast if the concepts used by R were * not previously registered via a call to - * @ref register_binding. + * \register_binding. * * Example: * \code diff --git a/boost/type_erasure/free.hpp b/boost/type_erasure/free.hpp index a2a6a7100a..23d1a67856 100644 --- a/boost/type_erasure/free.hpp +++ b/boost/type_erasure/free.hpp @@ -19,6 +19,9 @@ #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/control/if.hpp> +#include <boost/preprocessor/punctuation/is_begin_parens.hpp> +#include <boost/vmd/is_empty.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_cv.hpp> #include <boost/mpl/eval_if.hpp> @@ -148,6 +151,64 @@ struct first_placeholder_index : } \ } +/** INTERNAL ONLY */ +#define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name, N)\ + BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name, N) + +#ifdef BOOST_TYPE_ERASURE_DOXYGEN + +/** + * \brief Defines a primitive concept for a free function. + * + * \param concept_name is the name of the concept to declare. + * If it is omitted it defaults to <code>has_ ## function_name</code> + * \param function_name is the name of the function. + * + * The declaration of the concept is + * \code + * template<class Sig> + * struct concept_name; + * \endcode + * where Sig is a function type giving the + * signature of the function. + * + * This macro can only be used at namespace scope. + * + * Example: + * + * \code + * BOOST_TYPE_ERASURE_FREE(to_string) + * typedef has_to_string<std::string(_self const&)> to_string_concept; + * \endcode + * + * In C++03, the macro can only be used in the global namespace and + * is defined as: + * + * \code + * #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N) + * \endcode + * + * Example: + * + * \code + * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1) + * \endcode + * + * For backwards compatibility, this form is always accepted. + */ +#define BOOST_TYPE_ERASURE_FREE(concept_name, function_name) + +#else + +#define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N) \ + BOOST_TYPE_ERASURE_FREE_I( \ + qualified_name, \ + BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \ + function_name, \ + N) + +#endif + #else namespace boost { @@ -208,12 +269,143 @@ struct make_index_list<0> { typedef index_list<> type; }; -} -} -} +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \ + !defined(BOOST_NO_CXX11_DECLTYPE) + +template<int N> +using make_index_list_t = typename ::boost::type_erasure::detail::make_index_list<N>::type; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1900) + +template<class... T> +struct first_placeholder_index_ : + ::boost::type_erasure::detail::first_placeholder_index< + ::boost::remove_cv_t< ::boost::remove_reference_t<T> >... + > +{}; +template<class... T> +using first_placeholder_index_t = + typename ::boost::type_erasure::detail::first_placeholder_index_<T...>::type; + +#else + +template<class... T> +using first_placeholder_index_t = + typename ::boost::type_erasure::detail::first_placeholder_index< + ::boost::remove_cv_t< ::boost::remove_reference_t<T> >... + >::type; + +#endif + +template<class Base, class Tn, int I, class... T> +using free_param_t = + typename ::boost::mpl::eval_if_c<(::boost::type_erasure::detail::first_placeholder_index_t<T...>::value == I), + ::boost::type_erasure::detail::maybe_const_this_param<Tn, Base>, \ + ::boost::type_erasure::as_param<Base, Tn> + >::type; + +template<class Sig, class ID> +struct free_interface_chooser +{ + template<class Base, template<class> class C, template<class...> class F> + using apply = Base; +}; + +template<class R, class... A> +struct free_interface_chooser< + R(A...), + typename ::boost::type_erasure::detail::first_placeholder< + ::boost::remove_cv_t< ::boost::remove_reference_t<A> >...>::type> +{ + template<class Base, template<class> class C, template<class...> class F> + using apply = F<R(A...), Base, + ::boost::type_erasure::detail::make_index_list_t<sizeof...(A)> >; +}; + +template<class Sig, template<class> class C, template<class...> class F> +struct free_choose_interface { + template<class Concept, class Base, class ID> + using apply = typename free_interface_chooser<Sig, ID>::template apply<Base, C, F>; +}; /** INTERNAL ONLY */ -#define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N) \ +#define BOOST_TYPE_ERASURE_FREE_I(concept_name, function_name) \ +template<class Sig> \ +struct concept_name; \ + \ +namespace boost_type_erasure_impl { \ + \ +template<class Sig, class Base, class Idx> \ +struct concept_name ## _free_interface; \ +template<class R, class... T, class Base, int... I> \ +struct concept_name ## _free_interface<R(T...), Base, ::boost::type_erasure::index_list<I...> > : Base {\ + friend ::boost::type_erasure::rebind_any_t<Base, R> \ + function_name( \ + ::boost::type_erasure::detail::free_param_t<Base, T, I, T...>... t) \ + { \ + return ::boost::type_erasure::call( \ + concept_name<R(T...)>(), \ + std::forward< ::boost::type_erasure::detail::free_param_t<Base, T, I, T...> >(t)...);\ + } \ +}; \ + \ +template<class Sig> \ +struct concept_name ## free; \ + \ +template<class R, class... T> \ +struct concept_name ## free<R(T...)> { \ + static R apply(T... t) \ + { return function_name(std::forward<T>(t)...); } \ +}; \ + \ +template<class... T> \ +struct concept_name ## free<void(T...)> { \ + static void apply(T... t) \ + { function_name(std::forward<T>(t)...); } \ +}; \ + \ +} \ + \ +template<class Sig> \ +struct concept_name : \ + boost_type_erasure_impl::concept_name##free<Sig> \ +{}; \ + \ +template<class Sig> \ +::boost::type_erasure::detail::free_choose_interface<Sig, concept_name, \ + boost_type_erasure_impl::concept_name ## _free_interface> \ +boost_type_erasure_find_interface(concept_name<Sig>); + +#define BOOST_TYPE_ERASURE_FREE_SIMPLE(name, ...) \ + BOOST_TYPE_ERASURE_FREE_I(has_ ## name, name) + +#define BOOST_TYPE_ERASURE_FREE_NS_I(concept_name, name) \ + BOOST_TYPE_ERASURE_FREE_I(concept_name, name) + +#define BOOST_TYPE_ERASURE_FREE_NS(concept_name, name) \ + BOOST_TYPE_ERASURE_OPEN_NAMESPACE(concept_name) \ + BOOST_TYPE_ERASURE_FREE_NS_I(BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(concept_name)), concept_name), name) \ + BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(concept_name) + +#define BOOST_TYPE_ERASURE_FREE_NAMED(concept_name, name, ...) \ + BOOST_PP_IF(BOOST_PP_IS_BEGIN_PARENS(concept_name), \ + BOOST_TYPE_ERASURE_FREE_NS, \ + BOOST_TYPE_ERASURE_FREE_I) \ + (concept_name, name) + +#define BOOST_TYPE_ERASURE_FREE_CAT(x, y) x y + +#define BOOST_TYPE_ERASURE_FREE(name, ...) \ + BOOST_TYPE_ERASURE_FREE_CAT( \ + BOOST_PP_IF(BOOST_VMD_IS_EMPTY(__VA_ARGS__), \ + BOOST_TYPE_ERASURE_FREE_SIMPLE, \ + BOOST_TYPE_ERASURE_FREE_NAMED), \ + (name, __VA_ARGS__)) + +#else + +/** INTERNAL ONLY */ +#define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name) \ BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name) \ \ template<class Sig> \ @@ -273,41 +465,23 @@ struct make_index_list<0> { } \ } -#endif /** INTERNAL ONLY */ -#define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name, N)\ - BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name, N) +#define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name) \ + BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name) -/** - * \brief Defines a primitive concept for a free function. - * - * \param qualified_name should be a preprocessor sequence - * of the form (namespace1)(namespace2)...(concept_name). - * \param function_name is the name of the function. - * \param N is the number of arguments of the function. - * - * The declaration of the concept is - * \code - * template<class Sig> - * struct ::namespace1::namespace2::...::concept_name; - * \endcode - * where Sig is a function type giving the - * signature of the function. - * - * This macro can only be used in the global namespace. - * - * Example: - * - * \code - * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1) - * \endcode - */ -#define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N) \ +#define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, ...) \ BOOST_TYPE_ERASURE_FREE_I( \ qualified_name, \ BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \ - function_name, \ - N) + function_name) + +#endif + +} +} +} + +#endif #endif diff --git a/boost/type_erasure/is_placeholder.hpp b/boost/type_erasure/is_placeholder.hpp index 055ee621ad..a1e67fc165 100644 --- a/boost/type_erasure/is_placeholder.hpp +++ b/boost/type_erasure/is_placeholder.hpp @@ -12,16 +12,27 @@ #define BOOST_TYPE_ERASURE_DETAIL_IS_PLACEHOLDER_HPP_INCLUDED #include <boost/mpl/bool.hpp> -#include <boost/type_traits/is_base_and_derived.hpp> -#include <boost/type_erasure/placeholder.hpp> namespace boost { namespace type_erasure { +#ifdef BOOST_TYPE_ERASURE_DOXYGEN + /** A metafunction that indicates whether a type is a @ref placeholder. */ template<class T> -struct is_placeholder : ::boost::is_base_and_derived<placeholder, T> {}; +struct is_placeholder {}; + +#else + +template<class T, class Enable = void> +struct is_placeholder : ::boost::mpl::false_ {}; + +template<class T> +struct is_placeholder<T, typename T::_boost_type_erasure_is_placeholder> : + ::boost::mpl::true_ {}; + +#endif } } diff --git a/boost/type_erasure/is_subconcept.hpp b/boost/type_erasure/is_subconcept.hpp index aa8ee6585a..c327731094 100644 --- a/boost/type_erasure/is_subconcept.hpp +++ b/boost/type_erasure/is_subconcept.hpp @@ -11,6 +11,7 @@ #ifndef BOOST_TYPE_ERASURE_IS_SUBCONCEPT_HPP_INCLUDED #define BOOST_TYPE_ERASURE_IS_SUBCONCEPT_HPP_INCLUDED +#include <boost/mpl/and.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/if.hpp> @@ -19,6 +20,7 @@ #include <boost/mpl/has_key.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_erasure/detail/normalize.hpp> +#include <boost/type_erasure/detail/check_map.hpp> #include <boost/type_erasure/detail/rebind_placeholders.hpp> #include <boost/type_erasure/static_binding.hpp> @@ -26,10 +28,33 @@ namespace boost { namespace type_erasure { namespace detail { +#ifdef BOOST_TYPE_ERASURE_USE_MP11 + +template<class S, class K> +struct mp_set_has_key : ::boost::mp11::mp_set_contains<S, K> {}; + +template<class Super, class Bindings> +struct is_subconcept_f +{ + template<class T> + using apply = ::boost::mp11::mp_set_contains<Super, ::boost::type_erasure::detail::rebind_placeholders_t<T, Bindings> >; +}; + +template<class Super> +struct is_subconcept_f<Super, void> +{ + template<class T> + using apply = ::boost::mp11::mp_set_contains<Super, T>; +}; + +#endif + template<class Sub, class Super, class PlaceholderMap> struct is_subconcept_impl { +#ifndef BOOST_TYPE_ERASURE_USE_MP11 typedef typename ::boost::type_erasure::detail::normalize_concept< Super>::concept_set super_set; + typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< Super >::type placeholder_subs_super; @@ -68,6 +93,30 @@ struct is_subconcept_impl { >::type, typename ::boost::mpl::end<normalized_sub>::type >::type type; +#else + typedef ::boost::type_erasure::detail::normalize_concept_t<Super> super_set; + + typedef ::boost::type_erasure::detail::get_placeholder_normalization_map_t< + Super + > placeholder_subs_super; + + typedef ::boost::type_erasure::detail::normalize_concept_t<Sub> normalized_sub; + typedef ::boost::type_erasure::detail::get_placeholder_normalization_map_t< + Sub + > placeholder_subs_sub; + typedef ::boost::mp11::mp_eval_if_c< ::boost::is_same<PlaceholderMap, void>::value, + void, + ::boost::type_erasure::detail::convert_deductions_t, + PlaceholderMap, + placeholder_subs_sub, + placeholder_subs_super + > bindings; + + typedef typename ::boost::mp11::mp_all_of< + normalized_sub, + ::boost::type_erasure::detail::is_subconcept_f<super_set, bindings>::template apply + > type; +#endif }; } @@ -92,13 +141,24 @@ struct is_subconcept_impl { * are presumed to use the same set of placeholders. */ template<class Sub, class Super, class PlaceholderMap = void> -struct is_subconcept : ::boost::type_erasure::detail::is_subconcept_impl<Sub, Super, PlaceholderMap>::type { -}; +struct is_subconcept : + ::boost::mpl::and_< + ::boost::type_erasure::detail::check_map<Sub, PlaceholderMap>, + ::boost::type_erasure::detail::is_subconcept_impl<Sub, Super, PlaceholderMap> + >::type +{}; #ifndef BOOST_TYPE_ERASURE_DOXYGEN +template<class Sub, class Super> +struct is_subconcept<Sub, Super, void> : + ::boost::type_erasure::detail::is_subconcept_impl<Sub, Super, void>::type +{}; template<class Sub, class Super, class PlaceholderMap> struct is_subconcept<Sub, Super, static_binding<PlaceholderMap> > : - ::boost::type_erasure::detail::is_subconcept_impl<Sub, Super, PlaceholderMap>::type + ::boost::mpl::and_< + ::boost::type_erasure::detail::check_map<Sub, PlaceholderMap>, + ::boost::type_erasure::detail::is_subconcept_impl<Sub, Super, PlaceholderMap> + >::type {}; #endif diff --git a/boost/type_erasure/member.hpp b/boost/type_erasure/member.hpp index c20a348f47..d358cbad20 100644 --- a/boost/type_erasure/member.hpp +++ b/boost/type_erasure/member.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_TYPE_ERASURE_MEMBER_HPP_INCLUDED #define BOOST_TYPE_ERASURE_MEMBER_HPP_INCLUDED +#include <boost/type_erasure/detail/member11.hpp> + +#ifndef BOOST_TYPE_ERASURE_MEMBER + #include <boost/detail/workaround.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/dec.hpp> @@ -74,25 +78,54 @@ /** INTERNAL ONLY */ #define BOOST_TYPE_ERASURE_MEMBER_ENUM_ARGS(N) BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_MEMBER_ARG, ~) +#ifdef BOOST_TYPE_ERASURE_DOXYGEN + /** * \brief Defines a primitive concept for a member function. * - * \param qualified_name should be a preprocessor sequence - * of the form (namespace1)(namespace2)...(concept_name). + * \param concept_name is the name of the concept to declare. + * If it is omitted it defaults to <code>has_ ## member</code> * \param member is the name of the member function. - * \param N is the number of arguments of the function. * * The declaration of the concept is * \code * template<class Sig, class T = _self> - * struct ::namespace1::namespace2::...::concept_name; + * struct concept_name; + * \endcode + * where @c Sig is a function type giving the + * signature of the member function, and @c T is the + * object type. @c T may be const-qualified for + * const member functions. @c concept_name<R(A...) const, T> + * is an alias for @c concept_name<R(A...), const T>. + * + * This macro can only be used at namespace scope. + * + * Example: + * + * \code + * namespace boost { + * BOOST_TYPE_ERASURE_MEMBER(push_back) + * } + * typedef boost::has_push_back<void(int)> push_back_concept; + * \endcode + * + * The concept defined by this function may be specialized to + * provide a concept_map. The class object will be passed by + * reference as the first parameter. + * + * \code + * template<> + * struct has_push_back<void(int), std::list<int> > { + * static void apply(std::list<int>& l, int i) { l.push_back(i); } + * }; * \endcode - * where Sig is a function type giving the - * signature of the member function, and T is the - * object type. T may be const-qualified for - * const member functions. * - * This macro can only be used in the global namespace. + * In C++03, the macro can only be used in the global namespace and + * is defined as: + * + * \code + * #define BOOST_TYPE_ERASURE_MEMBER(qualified_name, member, N) + * \endcode * * Example: * @@ -101,9 +134,12 @@ * typedef boost::has_push_back<void(int), _self> push_back_concept; * \endcode * - * \note In C++11 the argument N is ignored and may be omitted. - * BOOST_TYPE_ERASURE_MEMBER will always define a variadic concept. + * For backwards compatibility, this form is always accepted. */ +#define BOOST_TYPE_ERASURE_MEMBER(concept_name, member) /**/ + +#else + #define BOOST_TYPE_ERASURE_MEMBER(qualified_name, member, N) \ BOOST_TYPE_ERASURE_MEMBER_I( \ qualified_name, \ @@ -111,6 +147,8 @@ member, \ N) +#endif + #else /** INTERNAL ONLY */ @@ -119,9 +157,14 @@ #define BOOST_TYPE_ERASURE_MEMBER_TPL_ARG_LIST(N, X) , class... A #define BOOST_TYPE_ERASURE_MEMBER_ENUM_PARAMS(N, X) X... -#define BOOST_TYPE_ERASURE_MEMBER_FORWARD_PARAMS(N, X, x) ::std::forward<X>(x)... +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_TYPE_ERASURE_MEMBER_FORWARD_PARAMS(N, X, x) ::std::forward<X>(x)... +# define BOOST_TYPE_ERASURE_MEMBER_FORWARD_REBIND(N) , ::std::forward<typename ::boost::type_erasure::as_param<Base, A>::type>(a)... +#else +# define BOOST_TYPE_ERASURE_MEMBER_FORWARD_PARAMS(N, X, x) x... +# define BOOST_TYPE_ERASURE_MEMBER_FORWARD_REBIND(N) , a... +#endif #define BOOST_TYPE_ERASURE_MEMBER_ENUM_TRAILING_PARAMS(N, X) , X... -#define BOOST_TYPE_ERASURE_MEMBER_FORWARD_REBIND(N) , ::std::forward<typename ::boost::type_erasure::as_param<Base, A>::type>(a)... #define BOOST_TYPE_ERASURE_MEMBER_ENUM_TRAILING_BINARY_PARAMS(N, X, x) , X... x #define BOOST_TYPE_ERASURE_MEMBER_ENUM_ARGS(N) typename ::boost::type_erasure::as_param<Base, A>::type... a @@ -242,3 +285,5 @@ BOOST_TYPE_ERASURE_MEMBER_II(namespace_name, concept_name, member, N) #endif + +#endif diff --git a/boost/type_erasure/operators.hpp b/boost/type_erasure/operators.hpp index 97fddbfbc6..059f41e091 100644 --- a/boost/type_erasure/operators.hpp +++ b/boost/type_erasure/operators.hpp @@ -28,9 +28,6 @@ namespace boost { namespace type_erasure { -template<class Concept, class Placeholder> -class any; - /** INTERNAL ONLY */ #define BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(name, op) \ template<class T = _self> \ diff --git a/boost/type_erasure/param.hpp b/boost/type_erasure/param.hpp index e3cce05898..7aca5e3c6b 100644 --- a/boost/type_erasure/param.hpp +++ b/boost/type_erasure/param.hpp @@ -27,12 +27,16 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class Concept, class T> class any; template<class Concept> class binding; +#endif + namespace detail { struct access; @@ -75,16 +79,6 @@ struct placeholder_conversion<T&&, T&&> : boost::mpl::true_ {}; } -#ifdef __clang__ -#if !__has_feature(cxx_reference_qualified_functions) -/** INTERNAL ONLY */ -#define BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS -#endif -#else -/** INTERNAL ONLY */ -#define BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS -#endif - /** * \brief A wrapper to help with overload resolution for functions * operating on an @ref any. @@ -96,8 +90,8 @@ struct placeholder_conversion<T&&, T&&> : boost::mpl::true_ {}; * with an @ref any that has the same @c Concept * and base placeholder when there exists a corresponding * standard conversion for the placeholder. - * A conversion sequence from @ref any<C, P> to @ref param<C, P1> is - * a better conversion sequence than @ref any<C, P> to @ref param<C, P2> + * A conversion sequence from @ref any "any<C, P>" to @ref param "param<C, P1>" is + * a better conversion sequence than @ref any "any<C, P>" to @ref param "param<C, P2>" * iff the corresponding placeholder standard conversion * sequence from P to P1 is a better conversion sequence than * P to P2. @@ -172,13 +166,19 @@ public: {} #endif + /** INTERNAL ONLY */ + param(const ::boost::type_erasure::detail::storage& data, + const ::boost::type_erasure::binding<Concept>& table) + : _impl(data, table) + {} + /** Returns the stored @ref any. */ any<Concept, T> get() const { return _impl; } private: any<Concept, T> _impl; }; -#ifndef BOOST_NO_FUNCTION_REFERENCE_QUALIFIERS +#if !defined(BOOST_NO_CXX11_REF_QUALIFIERS) && !defined(BOOST_TYPE_ERASURE_DOXYGEN) template<class Concept, class T> class param<Concept, const T&> { @@ -199,7 +199,21 @@ public: param(U& u, typename boost::enable_if< ::boost::is_same<U, const any<Concept, T> > >::type* = 0) : _impl(u) {} any<Concept, const T&> get() const { return _impl; } protected: - any<Concept, const T&> _impl; + struct _impl_t { + _impl_t(const ::boost::type_erasure::detail::storage& data_, + const ::boost::type_erasure::binding<Concept>& table_) + : table(table_), data(data_) + {} + _impl_t(const any<Concept, T>& u) + : table(::boost::type_erasure::detail::access::table(u)), + data(::boost::type_erasure::detail::access::data(u)) + {} + // It's safe to capture the table by reference, because + // the user's argument should out-live us. storage is + // just a void*, so we don't need to add indirection. + const ::boost::type_erasure::binding<Concept>& table; + ::boost::type_erasure::detail::storage data; + } _impl; }; template<class Concept, class T> @@ -257,7 +271,7 @@ public: /** * \brief Metafunction that creates a @ref param. * - * If @c T is a (cv/reference qualifed) placeholder, + * If @c T is a (cv/reference qualified) placeholder, * returns @ref param<@ref concept_of "concept_of<Any>::type", T>, * otherwise, returns T. This metafunction is intended * to be used for function arguments in specializations of @@ -280,6 +294,13 @@ struct as_param { #endif }; +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +template<class Any, class T> +using as_param_t = typename ::boost::type_erasure::as_param<Any, T>::type; + +#endif + } } diff --git a/boost/type_erasure/placeholder.hpp b/boost/type_erasure/placeholder.hpp index 0ea7ab5bce..1311f03bae 100644 --- a/boost/type_erasure/placeholder.hpp +++ b/boost/type_erasure/placeholder.hpp @@ -45,7 +45,10 @@ namespace type_erasure { * explicitly, but the substitution still works the * same way. */ -struct placeholder {}; +struct placeholder { + /// INTERNAL ONLY + typedef void _boost_type_erasure_is_placeholder; +}; struct _a : placeholder {}; struct _b : placeholder {}; diff --git a/boost/type_erasure/placeholder_of.hpp b/boost/type_erasure/placeholder_of.hpp index 8e8171898d..4a42b5744d 100644 --- a/boost/type_erasure/placeholder_of.hpp +++ b/boost/type_erasure/placeholder_of.hpp @@ -14,12 +14,16 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN + template<class Concept, class T> class any; template<class Concept, class T> class param; +#endif + /** * A metafunction returning the (const/reference qualified) placeholder * corresponding to an @ref any. It will also work for all bases @@ -52,6 +56,13 @@ struct placeholder_of< ::boost::type_erasure::param<Concept, T> > typedef T type; }; +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +template<class T> +using placeholder_of_t = typename ::boost::type_erasure::placeholder_of<T>::type; + +#endif + } } diff --git a/boost/type_erasure/rebind_any.hpp b/boost/type_erasure/rebind_any.hpp index 452e6893d8..be62cff723 100644 --- a/boost/type_erasure/rebind_any.hpp +++ b/boost/type_erasure/rebind_any.hpp @@ -20,8 +20,10 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN template<class Concept, class T> class any; +#endif /** * A metafunction that changes the @ref placeholder of @@ -36,6 +38,7 @@ class any; * \code * rebind_any<any<Concept>, _a>::type -> any<Concept, _a> * rebind_any<any<Concept>, _b&>::type -> any<Concept, _b&> + * rebind_any<any<Concept>, _c&&>::type -> any<Concept, _c&&> * rebind_any<any<Concept>, int>::type -> int * \endcode * @@ -62,6 +65,13 @@ struct rebind_any #endif }; +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +template<class Any, class T> +using rebind_any_t = typename ::boost::type_erasure::rebind_any<Any, T>::type; + +#endif + } } diff --git a/boost/type_erasure/register_binding.hpp b/boost/type_erasure/register_binding.hpp index 46364c9775..b0489b3ef0 100644 --- a/boost/type_erasure/register_binding.hpp +++ b/boost/type_erasure/register_binding.hpp @@ -53,7 +53,11 @@ struct append_to_key_static { append_to_key_static(key_type* k) : key(k) {} template<class P> void operator()(P) { +#ifndef BOOST_TYPE_ERASURE_USE_MP11 key->push_back(&typeid(typename ::boost::mpl::at<Map, P>::type)); +#else + key->push_back(&typeid(::boost::mp11::mp_second< ::boost::mp11::mp_map_find<Map, P> >)); +#endif } key_type* key; }; @@ -94,7 +98,11 @@ struct register_function { template<class F> void operator()(F) { key_type key; +#ifndef BOOST_TYPE_ERASURE_USE_MP11 typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mpl::set0<> >::type placeholders; +#else + typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mp11::mp_list<> >::type placeholders; +#endif typedef typename ::boost::mpl::fold< placeholders, ::boost::mpl::map0<>, @@ -111,7 +119,7 @@ struct register_function { /** * Registers a model of a concept to allow downcasting @ref any - * via @ref dynamic_any_cast. + * via \dynamic_any_cast. */ template<class Concept, class Map> void register_binding(const static_binding<Map>&) @@ -140,7 +148,11 @@ void register_binding() typedef typename normalized::first basic; typedef typename ::boost::mpl::fold< basic, +#ifndef BOOST_TYPE_ERASURE_USE_MP11 ::boost::mpl::set0<>, +#else + ::boost::mp11::mp_list<>, +#endif ::boost::type_erasure::detail::get_placeholders< ::boost::mpl::_2, ::boost::mpl::_1> >::type all_placeholders; // remove deduced placeholders diff --git a/boost/type_erasure/relaxed.hpp b/boost/type_erasure/relaxed.hpp index 69e57ec7cd..a9ada91df6 100644 --- a/boost/type_erasure/relaxed.hpp +++ b/boost/type_erasure/relaxed.hpp @@ -52,7 +52,7 @@ struct is_relaxed_impl : * - A raw value can be assigned to an @ref any. This will replace * the value stored by the @ref any. (But note that if @ref assignable * is present, it takes priority.) - * - copy assignment of @ref any uses the copy constructor if it can't + * - assignment of @ref any uses the constructor if it can't * use @ref assignable (either because @ref assignable is missing, * or because the stored types do not match). * - default construction of @ref any is allowed and creates a null any. diff --git a/boost/type_erasure/require_match.hpp b/boost/type_erasure/require_match.hpp index eada5eb7e6..8da4c6b827 100644 --- a/boost/type_erasure/require_match.hpp +++ b/boost/type_erasure/require_match.hpp @@ -32,8 +32,10 @@ namespace boost { namespace type_erasure { +#ifndef BOOST_TYPE_ERASURE_DOXYGEN template<class Concept> class binding; +#endif #ifdef BOOST_TYPE_ERASURE_DOXYGEN @@ -114,6 +116,8 @@ void require_match( ::boost::type_erasure::detail::require_match_impl(cond, table, op, ::std::forward<U>(arg)...); } +#ifndef BOOST_TYPE_ERASURE_USE_MP11 + template<class Op, class... U> void require_match( const Op& op, @@ -129,6 +133,25 @@ void require_match( #else +template<class Op, class... U> +void require_match( + const Op& op, + U&&... arg) +{ + ::boost::type_erasure::is_relaxed< + ::boost::type_erasure::detail::extract_concept_t< + ::boost::type_erasure::detail::get_args_t< + typename ::boost::type_erasure::detail::get_signature<Op>::type + >, + ::boost::mp11::mp_list< ::boost::remove_reference_t<U>...> > + > cond; + ::boost::type_erasure::detail::require_match_impl(cond, op, ::std::forward<U>(arg)...); +} + +#endif + +#else + #define BOOST_PP_FILENAME_1 <boost/type_erasure/require_match.hpp> #define BOOST_PP_ITERATION_LIMITS (0, BOOST_TYPE_ERASURE_MAX_ARITY) #include BOOST_PP_ITERATE() diff --git a/boost/type_erasure/static_binding.hpp b/boost/type_erasure/static_binding.hpp index 2da86ca3bc..371ac62e4c 100644 --- a/boost/type_erasure/static_binding.hpp +++ b/boost/type_erasure/static_binding.hpp @@ -21,7 +21,7 @@ namespace type_erasure { * \pre @c Map must be an MPL map whose keys are placeholders. */ template<class Map> -struct static_binding {}; +struct static_binding { typedef Map map_type; }; /** * A convenience function to prevent constructor calls |