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 #if !defined(BOOST_PP_IS_ITERATING) 12 13 #ifndef BOOST_TYPE_ERASURE_CALLABLE_HPP_INCLUDED 14 #define BOOST_TYPE_ERASURE_CALLABLE_HPP_INCLUDED 15 16 #include <boost/detail/workaround.hpp> 17 #include <boost/utility/declval.hpp> 18 #include <boost/mpl/vector.hpp> 19 #include <boost/mpl/push_back.hpp> 20 #include <boost/preprocessor/cat.hpp> 21 #include <boost/preprocessor/dec.hpp> 22 #include <boost/preprocessor/iteration/iterate.hpp> 23 #include <boost/preprocessor/repetition/enum.hpp> 24 #include <boost/preprocessor/repetition/enum_params.hpp> 25 #include <boost/preprocessor/repetition/enum_trailing_params.hpp> 26 #include <boost/preprocessor/repetition/enum_binary_params.hpp> 27 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> 28 #include <boost/type_erasure/config.hpp> 29 #include <boost/type_erasure/call.hpp> 30 #include <boost/type_erasure/concept_interface.hpp> 31 #include <boost/type_erasure/rebind_any.hpp> 32 #include <boost/type_erasure/param.hpp> 33 34 namespace boost { 35 namespace type_erasure { 36 37 template<class Sig, class F = _self> 38 struct callable; 39 40 namespace detail { 41 42 template<class Sig> 43 struct result_of_callable; 44 45 } 46 47 #if defined(BOOST_TYPE_ERASURE_DOXYGEN) 48 49 /** 50 * The @ref callable concept allows an @ref any to hold function objects. 51 * @c Sig is interpreted in the same way as for Boost.Function, except 52 * that the arguments and return type are allowed to be placeholders. 53 * @c F must be a @ref placeholder. 54 * 55 * Multiple instances of @ref callable can be used 56 * simultaneously. Overload resolution works normally. 57 * Note that unlike Boost.Function, @ref callable 58 * does not provide result_type. It does, however, 59 * support @c boost::result_of. 60 */ 61 template<class Sig, class F = _self> 62 struct callable 63 { 64 /** 65 * @c R is the result type of @c Sig and @c T is the argument 66 * types of @c Sig. 67 */ 68 static R apply(F& f, T... arg); 69 }; 70 71 #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ 72 !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ 73 !BOOST_WORKAROUND(BOOST_MSVC, == 1800) 74 75 template<class R, class... T, class F> 76 struct callable<R(T...), F> 77 { applyboost::type_erasure::callable78 static R apply(F& f, T... arg) 79 { 80 return f(std::forward<T>(arg)...); 81 } 82 }; 83 84 template<class... T, class F> 85 struct callable<void(T...), F> 86 { applyboost::type_erasure::callable87 static void apply(F& f, T... arg) 88 { 89 f(std::forward<T>(arg)...); 90 } 91 }; 92 93 template<class R, class F, class Base, class Enable, class... T> 94 struct concept_interface<callable<R(T...), F>, Base, F, Enable> 95 : Base 96 { 97 template<class Sig> 98 struct result : 99 ::boost::type_erasure::detail::result_of_callable<Sig> 100 {}; 101 typedef void _boost_type_erasure_is_callable; 102 typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; 103 typedef char (&_boost_type_erasure_callable_size)[1]; 104 _boost_type_erasure_callable_size 105 _boost_type_erasure_deduce_callable( 106 typename ::boost::type_erasure::as_param<Base, T>::type...); 107 typename ::boost::type_erasure::rebind_any<Base, R>::type operator ()boost::type_erasure::concept_interface108 operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) 109 { 110 return ::boost::type_erasure::call(callable<R(T...), F>(), *this, 111 ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); 112 } 113 }; 114 115 template<class R, class F, class Base, class Enable, class... T> 116 struct concept_interface<callable<R(T...), const F>, Base, F, Enable> 117 : Base 118 { 119 template<class Sig> 120 struct result : 121 ::boost::type_erasure::detail::result_of_callable<Sig> 122 {}; 123 typedef void _boost_type_erasure_is_callable; 124 typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; 125 typedef char (&_boost_type_erasure_callable_size)[1]; 126 _boost_type_erasure_callable_size 127 _boost_type_erasure_deduce_callable( 128 typename ::boost::type_erasure::as_param<Base, T>::type...) const; operator ()boost::type_erasure::concept_interface129 typename ::boost::type_erasure::rebind_any<Base, R>::type operator()( 130 typename ::boost::type_erasure::as_param<Base, T>::type... arg) const 131 { 132 return ::boost::type_erasure::call(callable<R(T...), const F>(), *this, 133 ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); 134 } 135 }; 136 137 template<class R, class F, class Base, class... T> 138 struct concept_interface< 139 callable<R(T...), F>, 140 Base, 141 F, 142 typename Base::_boost_type_erasure_is_callable 143 > 144 : Base 145 { 146 typedef typename ::boost::mpl::push_back< 147 typename Base::_boost_type_erasure_callable_results, 148 R 149 >::type _boost_type_erasure_callable_results; 150 typedef char (&_boost_type_erasure_callable_size)[ 151 ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; 152 using Base::_boost_type_erasure_deduce_callable; 153 _boost_type_erasure_callable_size 154 _boost_type_erasure_deduce_callable( 155 typename ::boost::type_erasure::as_param<Base, T>::type...); 156 using Base::operator(); 157 typename ::boost::type_erasure::rebind_any<Base, R>::type operator ()boost::type_erasure::concept_interface158 operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) 159 { 160 return ::boost::type_erasure::call(callable<R(T...), F>(), *this, 161 ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); 162 } 163 }; 164 165 template<class R, class F, class Base, class... T> 166 struct concept_interface< 167 callable<R(T...), const F>, 168 Base, 169 F, 170 typename Base::_boost_type_erasure_is_callable 171 > 172 : Base 173 { 174 typedef typename ::boost::mpl::push_back< 175 typename Base::_boost_type_erasure_callable_results, 176 R 177 >::type _boost_type_erasure_callable_results; 178 typedef char (&_boost_type_erasure_callable_size)[ 179 ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; 180 using Base::_boost_type_erasure_deduce_callable; 181 _boost_type_erasure_callable_size 182 _boost_type_erasure_deduce_callable( 183 typename ::boost::type_erasure::as_param<Base, T>::type...) const; 184 using Base::operator(); 185 typename ::boost::type_erasure::rebind_any<Base, R>::type operator ()boost::type_erasure::concept_interface186 operator()(typename ::boost::type_erasure::as_param<Base, T>::type... arg) const 187 { 188 return ::boost::type_erasure::call(callable<R(T...), const F>(), *this, 189 ::std::forward<typename ::boost::type_erasure::as_param<Base, T>::type>(arg)...); 190 } 191 }; 192 193 namespace detail { 194 195 template<class This, class... T> 196 struct result_of_callable<This(T...)> 197 { 198 typedef typename ::boost::mpl::at_c< 199 typename This::_boost_type_erasure_callable_results, 200 sizeof(::boost::declval<This>(). 201 _boost_type_erasure_deduce_callable(::boost::declval<T>()...)) - 1 202 >::type type; 203 }; 204 205 } 206 207 #else 208 209 /** INTERNAL ONLY */ 210 #define BOOST_PP_FILENAME_1 <boost/type_erasure/callable.hpp> 211 /** INTERNAL ONLY */ 212 #define BOOST_PP_ITERATION_LIMITS (0, BOOST_PP_DEC(BOOST_TYPE_ERASURE_MAX_ARITY)) 213 #include BOOST_PP_ITERATE() 214 215 #endif 216 217 } 218 } 219 220 #endif 221 222 #else 223 224 #define N BOOST_PP_ITERATION() 225 #define BOOST_TYPE_ERASURE_DECLVAL(z, n, data) ::boost::declval<BOOST_PP_CAT(T, n)>() 226 227 #define BOOST_TYPE_ERASURE_REBIND(z, n, data)\ 228 typename ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>::type BOOST_PP_CAT(arg, n) 229 230 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 231 #define BOOST_TYPE_ERASURE_FORWARD(z, n, data) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n) 232 #define BOOST_TYPE_ERASURE_FORWARD_REBIND(z, n, data) BOOST_PP_CAT(arg, n) 233 #else 234 #define BOOST_TYPE_ERASURE_FORWARD(z, n, data) ::std::forward<BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, data), n)>(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, data), n)) 235 #define BOOST_TYPE_ERASURE_FORWARD_REBIND(z, n, data) ::std::forward<typename ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>::type>(BOOST_PP_CAT(arg, n)) 236 #endif 237 238 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F> 239 struct callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F> 240 { applycallable241 static R apply(F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, T, arg)) 242 { 243 return f(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FORWARD, (T, arg))); 244 } 245 }; 246 247 template<BOOST_PP_ENUM_PARAMS(N, class T) BOOST_PP_COMMA_IF(N) class F> 248 struct callable<void(BOOST_PP_ENUM_PARAMS(N, T)), F> 249 { applycallable250 static void apply(F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N, T, arg)) 251 { 252 f(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FORWARD, (T, arg))); 253 } 254 }; 255 256 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base, class Enable> 257 struct concept_interface< 258 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>, 259 Base, 260 F, 261 Enable 262 > 263 : Base 264 { 265 template<class Sig> 266 struct result : 267 ::boost::type_erasure::detail::result_of_callable<Sig> 268 {}; 269 typedef void _boost_type_erasure_is_callable; 270 typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; 271 typedef char (&_boost_type_erasure_callable_size)[1]; 272 _boost_type_erasure_callable_size 273 _boost_type_erasure_deduce_callable( 274 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)); 275 typename ::boost::type_erasure::rebind_any<Base, R>::type 276 operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) 277 { 278 return ::boost::type_erasure::call( 279 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>(), 280 *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); 281 } 282 }; 283 284 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base, class Enable> 285 struct concept_interface< 286 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>, 287 Base, 288 F, 289 Enable 290 > 291 : Base 292 { 293 template<class Sig> 294 struct result : 295 ::boost::type_erasure::detail::result_of_callable<Sig> 296 {}; 297 typedef void _boost_type_erasure_is_callable; 298 typedef ::boost::mpl::vector<R> _boost_type_erasure_callable_results; 299 typedef char (&_boost_type_erasure_callable_size)[1]; 300 _boost_type_erasure_callable_size 301 _boost_type_erasure_deduce_callable( 302 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const; 303 typename ::boost::type_erasure::rebind_any<Base, R>::type 304 operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const 305 { 306 return ::boost::type_erasure::call( 307 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>(), 308 *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); 309 } 310 }; 311 312 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base> 313 struct concept_interface< 314 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>, 315 Base, 316 F, 317 typename Base::_boost_type_erasure_is_callable 318 > 319 : Base 320 { 321 typedef typename ::boost::mpl::push_back< 322 typename Base::_boost_type_erasure_callable_results, 323 R 324 >::type _boost_type_erasure_callable_results; 325 typedef char (&_boost_type_erasure_callable_size)[ 326 ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; 327 using Base::_boost_type_erasure_deduce_callable; 328 _boost_type_erasure_callable_size 329 _boost_type_erasure_deduce_callable( 330 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)); 331 using Base::operator(); 332 typename ::boost::type_erasure::rebind_any<Base, R>::type 333 operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) 334 { 335 return ::boost::type_erasure::call( 336 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), F>(), 337 *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); 338 } 339 }; 340 341 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class F, class Base> 342 struct concept_interface< 343 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>, 344 Base, 345 F, 346 typename Base::_boost_type_erasure_is_callable 347 > 348 : Base 349 { 350 typedef typename ::boost::mpl::push_back< 351 typename Base::_boost_type_erasure_callable_results, 352 R 353 >::type _boost_type_erasure_callable_results; 354 typedef char (&_boost_type_erasure_callable_size)[ 355 ::boost::mpl::size<_boost_type_erasure_callable_results>::value]; 356 using Base::_boost_type_erasure_deduce_callable; 357 _boost_type_erasure_callable_size 358 _boost_type_erasure_deduce_callable( 359 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const; 360 using Base::operator(); 361 typename ::boost::type_erasure::rebind_any<Base, R>::type 362 operator()(BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_REBIND, ~)) const 363 { 364 return ::boost::type_erasure::call( 365 callable<R(BOOST_PP_ENUM_PARAMS(N, T)), const F>(), 366 *this BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FORWARD_REBIND, ~)); 367 } 368 }; 369 370 namespace detail { 371 372 template<class This BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> 373 struct result_of_callable<This(BOOST_PP_ENUM_PARAMS(N, T))> 374 { 375 typedef typename ::boost::mpl::at_c< 376 typename This::_boost_type_erasure_callable_results, 377 sizeof(::boost::declval<This>(). 378 _boost_type_erasure_deduce_callable( 379 BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_DECLVAL, ~))) - 1 380 >::type type; 381 }; 382 383 } 384 385 #undef BOOST_TYPE_ERASURE_DECLVAL 386 #undef BOOST_TYPE_ERASURE_REBIND 387 #undef N 388 389 #endif 390