| 1 | // Boost.TypeErasure library |
| 2 | // |
| 3 | // Copyright 2011 Steven Watanabe |
| 4 | // |
| 5 | // Distributed under the Boost Software License Version 1.0. (See |
| 6 | // accompanying file LICENSE_1_0.txt or copy at |
| 7 | // http://www.boost.org/LICENSE_1_0.txt) |
| 8 | // |
| 9 | // $Id$ |
| 10 | |
| 11 | #ifndef BOOST_TYPE_ERASURE_PARAM_HPP_INCLUDED |
| 12 | #define BOOST_TYPE_ERASURE_PARAM_HPP_INCLUDED |
| 13 | |
| 14 | #include <boost/config.hpp> |
| 15 | #include <boost/utility/enable_if.hpp> |
| 16 | #include <boost/type_traits/is_same.hpp> |
| 17 | #include <boost/type_traits/add_const.hpp> |
| 18 | #include <boost/type_traits/remove_cv.hpp> |
| 19 | #include <boost/type_traits/remove_reference.hpp> |
| 20 | #include <boost/mpl/bool.hpp> |
| 21 | #include <boost/mpl/if.hpp> |
| 22 | #include <boost/type_erasure/detail/access.hpp> |
| 23 | #include <boost/type_erasure/detail/storage.hpp> |
| 24 | #include <boost/type_erasure/is_placeholder.hpp> |
| 25 | #include <boost/type_erasure/concept_of.hpp> |
| 26 | |
| 27 | namespace boost { |
| 28 | namespace type_erasure { |
| 29 | |
| 30 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN |
| 31 | |
| 32 | template<class Concept, class T> |
| 33 | class any; |
| 34 | |
| 35 | template<class Concept> |
| 36 | class binding; |
| 37 | |
| 38 | #endif |
| 39 | |
| 40 | namespace detail { |
| 41 | |
| 42 | struct access; |
| 43 | |
| 44 | } |
| 45 | |
| 46 | namespace detail { |
| 47 | |
| 48 | template<class From, class To> |
| 49 | struct placeholder_conversion : boost::mpl::false_ {}; |
| 50 | template<class T> |
| 51 | struct placeholder_conversion<T, T> : boost::mpl::true_ {}; |
| 52 | template<class T> |
| 53 | struct placeholder_conversion<T, T&> : boost::mpl::true_ {}; |
| 54 | template<class T> |
| 55 | struct placeholder_conversion<T, const T&> : boost::mpl::true_ {}; |
| 56 | template<class T> |
| 57 | struct placeholder_conversion<const T, T> : boost::mpl::true_ {}; |
| 58 | template<class T> |
| 59 | struct placeholder_conversion<const T, const T&> : boost::mpl::true_ {}; |
| 60 | template<class T> |
| 61 | struct placeholder_conversion<T&, T> : boost::mpl::true_ {}; |
| 62 | template<class T> |
| 63 | struct placeholder_conversion<T&, T&> : boost::mpl::true_ {}; |
| 64 | template<class T> |
| 65 | struct placeholder_conversion<T&, const T&> : boost::mpl::true_ {}; |
| 66 | template<class T> |
| 67 | struct placeholder_conversion<const T&, T> : boost::mpl::true_ {}; |
| 68 | template<class T> |
| 69 | struct placeholder_conversion<const T&, const T&> : boost::mpl::true_ {}; |
| 70 | |
| 71 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| 72 | template<class T> |
| 73 | struct placeholder_conversion<T&&, T> : boost::mpl::true_ {}; |
| 74 | template<class T> |
| 75 | struct placeholder_conversion<T&&, const T&> : boost::mpl::true_ {}; |
| 76 | template<class T> |
| 77 | struct placeholder_conversion<T&&, T&&> : boost::mpl::true_ {}; |
| 78 | #endif |
| 79 | |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * \brief A wrapper to help with overload resolution for functions |
| 84 | * operating on an @ref any. |
| 85 | * |
| 86 | * The template arguments are interpreted in |
| 87 | * the same way as @ref any. |
| 88 | * |
| 89 | * A parameter of type @ref param can be initialized |
| 90 | * with an @ref any that has the same @c Concept |
| 91 | * and base placeholder when there exists a corresponding |
| 92 | * standard conversion for the placeholder. |
| 93 | * A conversion sequence from @ref any "any<C, P>" to @ref param "param<C, P1>" is |
| 94 | * a better conversion sequence than @ref any "any<C, P>" to @ref param "param<C, P2>" |
| 95 | * iff the corresponding placeholder standard conversion |
| 96 | * sequence from P to P1 is a better conversion sequence than |
| 97 | * P to P2. |
| 98 | * |
| 99 | * \note Overloading based on cv-qualifiers and rvalue-ness is |
| 100 | * only supported in C++11. In C++03, all conversion sequences |
| 101 | * from @ref any to @ref param have the same rank. |
| 102 | * |
| 103 | * Example: |
| 104 | * |
| 105 | * \code |
| 106 | * void f(param<C, _a&>); |
| 107 | * void f(param<C, const _a&>); |
| 108 | * void g(param<C, const _a&>); |
| 109 | * void g(param<C, _a&&>); |
| 110 | * |
| 111 | * any<C, _a> a; |
| 112 | * f(any<C, _a>()); // calls void f(param<C, const _a&>); |
| 113 | * f(a); // calls void f(param<C, _a&>); (ambiguous in C++03) |
| 114 | * g(any<C, _a>()); // calls void g(param<C, _a&&>); (ambiguous in C++03) |
| 115 | * g(a); // calls void g(param<C, const _a&>); |
| 116 | * \endcode |
| 117 | * |
| 118 | */ |
| 119 | template<class Concept, class T> |
| 120 | class param { |
| 121 | public: |
| 122 | |
| 123 | friend struct boost::type_erasure::detail::access; |
| 124 | |
| 125 | /** INTERNAL ONLY */ |
| 126 | typedef void _boost_type_erasure_is_any; |
| 127 | /** INTERNAL ONLY */ |
| 128 | typedef param _boost_type_erasure_derived_type; |
| 129 | |
| 130 | template<class U> |
| 131 | param(any<Concept, U>& a |
| 132 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN |
| 133 | , typename boost::enable_if< |
| 134 | ::boost::type_erasure::detail::placeholder_conversion<U, T> |
| 135 | >::type* = 0 |
| 136 | #endif |
| 137 | ) |
| 138 | : _impl(a) |
| 139 | {} |
| 140 | template<class U> |
| 141 | param(const any<Concept, U>& a |
| 142 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN |
| 143 | , typename boost::enable_if< |
| 144 | ::boost::type_erasure::detail::placeholder_conversion< |
| 145 | typename ::boost::add_const<U>::type, |
| 146 | T |
| 147 | > |
| 148 | >::type* = 0 |
| 149 | #endif |
| 150 | ) |
| 151 | : _impl(a) |
| 152 | {} |
| 153 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| 154 | template<class U> |
| 155 | param(any<Concept, U>&& a |
| 156 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN |
| 157 | , typename boost::enable_if< |
| 158 | ::boost::type_erasure::detail::placeholder_conversion< |
| 159 | U&&, |
| 160 | T |
| 161 | > |
| 162 | >::type* = 0 |
| 163 | #endif |
| 164 | ) |
| 165 | : _impl(std::move(a)) |
| 166 | {} |
| 167 | #endif |
| 168 | |
| 169 | /** INTERNAL ONLY */ |
| 170 | param(const ::boost::type_erasure::detail::storage& data, |
| 171 | const ::boost::type_erasure::binding<Concept>& table) |
| 172 | : _impl(data, table) |
| 173 | {} |
| 174 | |
| 175 | /** Returns the stored @ref any. */ |
| 176 | any<Concept, T> get() const { return _impl; } |
| 177 | private: |
| 178 | any<Concept, T> _impl; |
| 179 | }; |
| 180 | |
| 181 | #if !defined(BOOST_NO_CXX11_REF_QUALIFIERS) && !defined(BOOST_TYPE_ERASURE_DOXYGEN) |
| 182 | |
| 183 | template<class Concept, class T> |
| 184 | class param<Concept, const T&> { |
| 185 | public: |
| 186 | |
| 187 | friend struct boost::type_erasure::detail::access; |
| 188 | |
| 189 | /** INTERNAL ONLY */ |
| 190 | typedef void _boost_type_erasure_is_any; |
| 191 | /** INTERNAL ONLY */ |
| 192 | typedef param _boost_type_erasure_derived_type; |
| 193 | |
| 194 | param(const ::boost::type_erasure::detail::storage& data, |
| 195 | const ::boost::type_erasure::binding<Concept>& table) |
| 196 | : _impl(data, table) |
| 197 | {} |
| 198 | template<class U> |
| 199 | param(U& u, typename boost::enable_if< ::boost::is_same<U, const any<Concept, T> > >::type* = 0) : _impl(u) {} |
| 200 | any<Concept, const T&> get() const { return _impl; } |
| 201 | protected: |
| 202 | struct _impl_t { |
| 203 | _impl_t(const ::boost::type_erasure::detail::storage& data_, |
| 204 | const ::boost::type_erasure::binding<Concept>& table_) |
| 205 | : table(table_), data(data_) |
| 206 | {} |
| 207 | _impl_t(const any<Concept, T>& u) |
| 208 | : table(::boost::type_erasure::detail::access::table(u)), |
| 209 | data(::boost::type_erasure::detail::access::data(u)) |
| 210 | {} |
| 211 | // It's safe to capture the table by reference, because |
| 212 | // the user's argument should out-live us. storage is |
| 213 | // just a void*, so we don't need to add indirection. |
| 214 | const ::boost::type_erasure::binding<Concept>& table; |
| 215 | ::boost::type_erasure::detail::storage data; |
| 216 | } _impl; |
| 217 | }; |
| 218 | |
| 219 | template<class Concept, class T> |
| 220 | class param<Concept, T&> : public param<Concept, const T&> { |
| 221 | public: |
| 222 | |
| 223 | friend struct boost::type_erasure::detail::access; |
| 224 | |
| 225 | /** INTERNAL ONLY */ |
| 226 | typedef void _boost_type_erasure_is_any; |
| 227 | /** INTERNAL ONLY */ |
| 228 | typedef param _boost_type_erasure_derived_type; |
| 229 | |
| 230 | param(const ::boost::type_erasure::detail::storage& data, |
| 231 | const ::boost::type_erasure::binding<Concept>& table) |
| 232 | : param<Concept, const T&>(data, table) |
| 233 | {} |
| 234 | any<Concept, T&> get() const |
| 235 | { |
| 236 | return any<Concept, T&>( |
| 237 | ::boost::type_erasure::detail::access::data(this->_impl), |
| 238 | ::boost::type_erasure::detail::access::table(this->_impl)); |
| 239 | } |
| 240 | }; |
| 241 | |
| 242 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
| 243 | |
| 244 | template<class Concept, class T> |
| 245 | class param<Concept, T&&> : public param<Concept, const T&> { |
| 246 | public: |
| 247 | |
| 248 | friend struct boost::type_erasure::detail::access; |
| 249 | |
| 250 | /** INTERNAL ONLY */ |
| 251 | typedef void _boost_type_erasure_is_any; |
| 252 | /** INTERNAL ONLY */ |
| 253 | typedef param _boost_type_erasure_derived_type; |
| 254 | |
| 255 | param(const ::boost::type_erasure::detail::storage& data, |
| 256 | const ::boost::type_erasure::binding<Concept>& table) |
| 257 | : param<Concept, const T&>(data, table) |
| 258 | {} |
| 259 | any<Concept, T&&> get() const |
| 260 | { |
| 261 | return any<Concept, T&&>( |
| 262 | ::boost::type_erasure::detail::access::data(this->_impl), |
| 263 | ::boost::type_erasure::detail::access::table(this->_impl)); |
| 264 | } |
| 265 | }; |
| 266 | |
| 267 | #endif |
| 268 | |
| 269 | #endif |
| 270 | |
| 271 | /** |
| 272 | * \brief Metafunction that creates a @ref param. |
| 273 | * |
| 274 | * If @c T is a (cv/reference qualified) placeholder, |
| 275 | * returns @ref param<@ref concept_of "concept_of<Any>::type", T>, |
| 276 | * otherwise, returns T. This metafunction is intended |
| 277 | * to be used for function arguments in specializations of |
| 278 | * @ref concept_interface. |
| 279 | * |
| 280 | * \see derived, rebind_any |
| 281 | */ |
| 282 | template<class Any, class T> |
| 283 | struct as_param { |
| 284 | #ifdef BOOST_TYPE_ERASURE_DOXYGEN |
| 285 | typedef detail::unspecified type; |
| 286 | #else |
| 287 | typedef typename ::boost::mpl::if_< |
| 288 | ::boost::type_erasure::is_placeholder< |
| 289 | typename ::boost::remove_cv< |
| 290 | typename ::boost::remove_reference<T>::type>::type>, |
| 291 | param<typename ::boost::type_erasure::concept_of<Any>::type, T>, |
| 292 | T |
| 293 | >::type type; |
| 294 | #endif |
| 295 | }; |
| 296 | |
| 297 | #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES |
| 298 | |
| 299 | template<class Any, class T> |
| 300 | using as_param_t = typename ::boost::type_erasure::as_param<Any, T>::type; |
| 301 | |
| 302 | #endif |
| 303 | |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | #endif |
| 308 | |