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> param(any<Concept,U> & a,typename boost::enable_if<::boost::type_erasure::detail::placeholder_conversion<U,T>>::type * =0)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> param(const any<Concept,U> & a,typename boost::enable_if<::boost::type_erasure::detail::placeholder_conversion<typename::boost::add_const<U>::type,T>>::type * =0)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> param(any<Concept,U> && a,typename boost::enable_if<::boost::type_erasure::detail::placeholder_conversion<U &&,T>>::type * =0)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 */ param(const::boost::type_erasure::detail::storage & data,const::boost::type_erasure::binding<Concept> & table)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. */ get() const176 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 param(const::boost::type_erasure::detail::storage & data,const::boost::type_erasure::binding<Concept> & table)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> param(U & u,typename boost::enable_if<::boost::is_same<U,const any<Concept,T>>>::type * =0)199 param(U& u, typename boost::enable_if< ::boost::is_same<U, const any<Concept, T> > >::type* = 0) : _impl(u) {} get() const200 any<Concept, const T&> get() const { return _impl; } 201 protected: 202 struct _impl_t { _impl_tboost::type_erasure::param::_impl_t203 _impl_t(const ::boost::type_erasure::detail::storage& data_, 204 const ::boost::type_erasure::binding<Concept>& table_) 205 : table(table_), data(data_) 206 {} _impl_tboost::type_erasure::param::_impl_t207 _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 param(const::boost::type_erasure::detail::storage & data,const::boost::type_erasure::binding<Concept> & table)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 {} get() const234 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 param(const::boost::type_erasure::detail::storage & data,const::boost::type_erasure::binding<Concept> & table)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 {} get() const259 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