| 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_OPERATORS_HPP_INCLUDED |
| 12 | #define BOOST_TYPE_ERASURE_OPERATORS_HPP_INCLUDED |
| 13 | |
| 14 | #include <iosfwd> |
| 15 | #include <boost/utility/enable_if.hpp> |
| 16 | #include <boost/type_erasure/detail/const.hpp> |
| 17 | #include <boost/type_erasure/call.hpp> |
| 18 | #include <boost/type_erasure/concept_interface.hpp> |
| 19 | #include <boost/type_erasure/placeholder.hpp> |
| 20 | #include <boost/type_erasure/concept_of.hpp> |
| 21 | #include <boost/type_erasure/derived.hpp> |
| 22 | #include <boost/type_erasure/rebind_any.hpp> |
| 23 | #include <boost/type_erasure/param.hpp> |
| 24 | #include <boost/type_erasure/check_match.hpp> |
| 25 | #include <boost/type_erasure/relaxed.hpp> |
| 26 | #include <boost/type_erasure/typeid_of.hpp> |
| 27 | |
| 28 | namespace boost { |
| 29 | namespace type_erasure { |
| 30 | |
| 31 | /** INTERNAL ONLY */ |
| 32 | #define BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(name, op) \ |
| 33 | template<class T = _self> \ |
| 34 | struct name \ |
| 35 | { \ |
| 36 | static void apply(T& arg) { op arg; } \ |
| 37 | }; \ |
| 38 | \ |
| 39 | template<class T, class Base> \ |
| 40 | struct concept_interface<name<T>, Base, T, \ |
| 41 | typename ::boost::enable_if< \ |
| 42 | detail::should_be_non_const<T, Base> \ |
| 43 | >::type \ |
| 44 | > : Base \ |
| 45 | { \ |
| 46 | typedef typename ::boost::type_erasure::derived<Base>::type _derived; \ |
| 47 | _derived& operator op() \ |
| 48 | { \ |
| 49 | ::boost::type_erasure::call(name<T>(), *this); \ |
| 50 | return static_cast<_derived&>(*this); \ |
| 51 | } \ |
| 52 | typename ::boost::type_erasure::rebind_any<Base, T>::type operator op(int) \ |
| 53 | { \ |
| 54 | typename ::boost::type_erasure::rebind_any<Base, T>::type result( \ |
| 55 | static_cast<_derived&>(*this)); \ |
| 56 | ::boost::type_erasure::call(name<T>(), *this); \ |
| 57 | return result; \ |
| 58 | } \ |
| 59 | }; \ |
| 60 | \ |
| 61 | template<class T, class Base> \ |
| 62 | struct concept_interface<name<T>, Base, T, \ |
| 63 | typename ::boost::enable_if< \ |
| 64 | detail::should_be_const<T, Base> \ |
| 65 | >::type \ |
| 66 | > : Base \ |
| 67 | { \ |
| 68 | typedef typename ::boost::type_erasure::derived<Base>::type _derived; \ |
| 69 | const _derived& operator op() const \ |
| 70 | { \ |
| 71 | ::boost::type_erasure::call(name<T>(), *this); \ |
| 72 | return static_cast<const _derived&>(*this); \ |
| 73 | } \ |
| 74 | typename ::boost::type_erasure::rebind_any<Base, T>::type operator op(int) const \ |
| 75 | { \ |
| 76 | typename ::boost::type_erasure::rebind_any<Base, T>::type result( \ |
| 77 | static_cast<const _derived&>(*this)); \ |
| 78 | ::boost::type_erasure::call(name<T>(), *this); \ |
| 79 | return result; \ |
| 80 | } \ |
| 81 | }; |
| 82 | |
| 83 | /** |
| 84 | * The @ref incrementable concept allow pre and |
| 85 | * post increment on an @ref any. The contained |
| 86 | * type must provide a pre-increment operator. |
| 87 | */ |
| 88 | BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(incrementable, ++) |
| 89 | /** |
| 90 | * The @ref decrementable concept allow pre and |
| 91 | * post decrement on an @ref any. The contained |
| 92 | * type must provide a pre-decrement operator. |
| 93 | */ |
| 94 | BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(decrementable, --) |
| 95 | |
| 96 | #undef BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR |
| 97 | |
| 98 | /** INTERNAL ONLY */ |
| 99 | #define BOOST_TYPE_ERASURE_UNARY_OPERATOR(name, op) \ |
| 100 | template<class T = _self, class R = T> \ |
| 101 | struct name \ |
| 102 | { \ |
| 103 | static R apply(const T& arg) { return op arg; } \ |
| 104 | }; \ |
| 105 | \ |
| 106 | template<class T, class R, class Base> \ |
| 107 | struct concept_interface<name<T, R>, Base, T> : Base \ |
| 108 | { \ |
| 109 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator op() const \ |
| 110 | { \ |
| 111 | return ::boost::type_erasure::call(name<T, R>(), *this); \ |
| 112 | } \ |
| 113 | }; |
| 114 | |
| 115 | /** |
| 116 | * The @ref complementable concept allow use of the bitwise |
| 117 | * complement operator on an @ref any. |
| 118 | */ |
| 119 | BOOST_TYPE_ERASURE_UNARY_OPERATOR(complementable, ~) |
| 120 | /** |
| 121 | * The @ref negatable concept allow use of the unary |
| 122 | * minus operator on an @ref any. |
| 123 | */ |
| 124 | BOOST_TYPE_ERASURE_UNARY_OPERATOR(negatable, -) |
| 125 | |
| 126 | #undef BOOST_TYPE_ERASURE_UNARY_OPERATOR |
| 127 | |
| 128 | template<class R, class T = _self> |
| 129 | struct dereferenceable |
| 130 | { |
| 131 | static R apply(const T& arg) { return *arg; } |
| 132 | }; |
| 133 | |
| 134 | /// \cond show_operators |
| 135 | |
| 136 | template<class R, class T, class Base> |
| 137 | struct concept_interface<dereferenceable<R, T>, Base, T> : Base |
| 138 | { |
| 139 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator*() const |
| 140 | { |
| 141 | return ::boost::type_erasure::call(dereferenceable<R, T>(), *this); |
| 142 | } |
| 143 | }; |
| 144 | |
| 145 | /// \endcond |
| 146 | |
| 147 | /** INTERNAL ONLY */ |
| 148 | #define BOOST_TYPE_ERASURE_BINARY_OPERATOR(name, op) \ |
| 149 | template<class T = _self, class U = T, class R = T> \ |
| 150 | struct name \ |
| 151 | { \ |
| 152 | static R apply(const T& lhs, const U& rhs) { return lhs op rhs; } \ |
| 153 | }; \ |
| 154 | \ |
| 155 | template<class T, class U, class R, class Base> \ |
| 156 | struct concept_interface<name<T, U, R>, Base, T> : Base \ |
| 157 | { \ |
| 158 | friend typename rebind_any<Base, R>::type \ |
| 159 | operator op(const typename derived<Base>::type& lhs, \ |
| 160 | typename as_param<Base, const U&>::type rhs) \ |
| 161 | { \ |
| 162 | return ::boost::type_erasure::call(name<T, U, R>(), lhs, rhs); \ |
| 163 | } \ |
| 164 | }; \ |
| 165 | \ |
| 166 | template<class T, class U, class R, class Base> \ |
| 167 | struct concept_interface< \ |
| 168 | name<T, U, R>, \ |
| 169 | Base, \ |
| 170 | U, \ |
| 171 | typename ::boost::disable_if< \ |
| 172 | ::boost::type_erasure::is_placeholder<T> >::type \ |
| 173 | > : Base \ |
| 174 | { \ |
| 175 | friend typename rebind_any<Base, R>::type \ |
| 176 | operator op(const T& lhs, \ |
| 177 | const typename derived<Base>::type& rhs) \ |
| 178 | { \ |
| 179 | return ::boost::type_erasure::call(name<T, U, R>(), lhs, rhs); \ |
| 180 | } \ |
| 181 | }; |
| 182 | |
| 183 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(addable, +) |
| 184 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(subtractable, -) |
| 185 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(multipliable, *) |
| 186 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(dividable, /) |
| 187 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(modable, %) |
| 188 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(left_shiftable, <<) |
| 189 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(right_shiftable, >>) |
| 190 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitandable, &) |
| 191 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitorable, |) |
| 192 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitxorable, ^) |
| 193 | |
| 194 | #undef BOOST_TYPE_ERASURE_BINARY_OPERATOR |
| 195 | |
| 196 | /** INTERNAL ONLY */ |
| 197 | #define BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(name, op) \ |
| 198 | template<class T = _self, class U = T> \ |
| 199 | struct name \ |
| 200 | { \ |
| 201 | static void apply(T& lhs, const U& rhs) { lhs op rhs; } \ |
| 202 | }; \ |
| 203 | \ |
| 204 | template<class T, class U, class Base> \ |
| 205 | struct concept_interface<name<T, U>, Base, T, \ |
| 206 | typename ::boost::disable_if< \ |
| 207 | ::boost::is_same< \ |
| 208 | typename ::boost::type_erasure::placeholder_of<Base>::type, \ |
| 209 | const T& \ |
| 210 | > \ |
| 211 | >::type \ |
| 212 | > : Base \ |
| 213 | { \ |
| 214 | friend typename detail::non_const_this_param<Base>::type& \ |
| 215 | operator op(typename detail::non_const_this_param<Base>::type& lhs, \ |
| 216 | typename as_param<Base, const U&>::type rhs) \ |
| 217 | { \ |
| 218 | ::boost::type_erasure::call(name<T, U>(),lhs, rhs); \ |
| 219 | return lhs; \ |
| 220 | } \ |
| 221 | }; \ |
| 222 | \ |
| 223 | template<class T, class U, class Base> \ |
| 224 | struct concept_interface< \ |
| 225 | name<T, U>, \ |
| 226 | Base, \ |
| 227 | U, \ |
| 228 | typename ::boost::disable_if< \ |
| 229 | ::boost::type_erasure::is_placeholder<T> >::type \ |
| 230 | > : Base \ |
| 231 | { \ |
| 232 | friend T& \ |
| 233 | operator op(T& lhs, const typename derived<Base>::type& rhs) \ |
| 234 | { \ |
| 235 | ::boost::type_erasure::call(name<T, U>(),lhs, rhs); \ |
| 236 | return lhs; \ |
| 237 | } \ |
| 238 | }; |
| 239 | |
| 240 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(add_assignable, +=) |
| 241 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(subtract_assignable, -=) |
| 242 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(multiply_assignable, *=) |
| 243 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(divide_assignable, /=) |
| 244 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(mod_assignable, %=) |
| 245 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(left_shift_assignable, <<=) |
| 246 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(right_shift_assignable, >>=) |
| 247 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitand_assignable, &=) |
| 248 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitor_assignable, |=) |
| 249 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitxor_assignable, ^=) |
| 250 | |
| 251 | #undef BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR |
| 252 | |
| 253 | template<class T = _self, class U = T> |
| 254 | struct equality_comparable |
| 255 | { |
| 256 | static bool apply(const T& lhs, const U& rhs) { return lhs == rhs; } |
| 257 | }; |
| 258 | |
| 259 | /// \cond show_operators |
| 260 | |
| 261 | template<class T, class U, class Base> |
| 262 | struct concept_interface<equality_comparable<T, U>, Base, T> : Base |
| 263 | { |
| 264 | friend bool operator==(const typename derived<Base>::type& lhs, |
| 265 | typename as_param<Base, const U&>::type rhs) |
| 266 | { |
| 267 | if(::boost::type_erasure::check_match(equality_comparable<T, U>(), lhs, rhs)) { |
| 268 | return ::boost::type_erasure::unchecked_call(equality_comparable<T, U>(), lhs, rhs); |
| 269 | } else { |
| 270 | return false; |
| 271 | } |
| 272 | } |
| 273 | friend bool operator!=(const typename derived<Base>::type& lhs, |
| 274 | typename as_param<Base, const U&>::type rhs) |
| 275 | { |
| 276 | return !(lhs == rhs); |
| 277 | } |
| 278 | }; |
| 279 | |
| 280 | template<class T, class U, class Base> |
| 281 | struct concept_interface< |
| 282 | equality_comparable<T, U>, |
| 283 | Base, |
| 284 | U, |
| 285 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<T> >::type |
| 286 | > : Base |
| 287 | { |
| 288 | friend bool operator==(const T& lhs, const typename derived<Base>::type& rhs) |
| 289 | { |
| 290 | return ::boost::type_erasure::call(equality_comparable<T, U>(), lhs, rhs); |
| 291 | } |
| 292 | friend bool operator!=(const T& lhs, const typename derived<Base>::type& rhs) |
| 293 | { |
| 294 | return !(lhs == rhs); |
| 295 | } |
| 296 | }; |
| 297 | |
| 298 | /// \endcond |
| 299 | |
| 300 | template<class T = _self, class U = T> |
| 301 | struct less_than_comparable |
| 302 | { |
| 303 | static bool apply(const T& lhs, const U& rhs) { return lhs < rhs; } |
| 304 | }; |
| 305 | |
| 306 | namespace detail { |
| 307 | |
| 308 | template<class F, class T, class U> |
| 309 | bool less_impl(const F& f, const T& lhs, const U& rhs, ::boost::mpl::true_) |
| 310 | { |
| 311 | if(::boost::type_erasure::check_match(f, lhs, rhs)) { |
| 312 | return ::boost::type_erasure::unchecked_call(f, lhs, rhs); |
| 313 | } else { |
| 314 | return ::boost::type_erasure::typeid_of( |
| 315 | static_cast<const typename derived<T>::type&>(lhs) |
| 316 | ).before( |
| 317 | ::boost::type_erasure::typeid_of( |
| 318 | static_cast<const typename derived<U>::type&>(rhs) |
| 319 | ) |
| 320 | ) != false; |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | template<class F, class T, class U> |
| 325 | bool less_impl(const F& f, const T& lhs, const U& rhs, ::boost::mpl::false_) |
| 326 | { |
| 327 | return ::boost::type_erasure::call(f, lhs, rhs); |
| 328 | } |
| 329 | |
| 330 | } |
| 331 | |
| 332 | /// \cond show_operators |
| 333 | |
| 334 | template<class T, class Base> |
| 335 | struct concept_interface<less_than_comparable<T, T>, Base, T> : Base |
| 336 | { |
| 337 | friend bool operator<(const typename derived<Base>::type& lhs, |
| 338 | typename as_param<Base, const T&>::type rhs) |
| 339 | { |
| 340 | return ::boost::type_erasure::detail::less_impl( |
| 341 | less_than_comparable<T, T>(), |
| 342 | lhs, rhs, |
| 343 | ::boost::type_erasure::is_relaxed< |
| 344 | typename ::boost::type_erasure::concept_of<Base>::type>()); |
| 345 | } |
| 346 | friend bool operator>=(const typename derived<Base>::type& lhs, |
| 347 | typename as_param<Base, const T&>::type rhs) |
| 348 | { |
| 349 | return !(lhs < rhs); |
| 350 | } |
| 351 | friend bool operator>(typename as_param<Base, const T&>::type lhs, |
| 352 | const typename derived<Base>::type& rhs) |
| 353 | { |
| 354 | return rhs < lhs; |
| 355 | } |
| 356 | friend bool operator<=(typename as_param<Base, const T&>::type lhs, |
| 357 | const typename derived<Base>::type& rhs) |
| 358 | { |
| 359 | return !(rhs < lhs); |
| 360 | } |
| 361 | }; |
| 362 | |
| 363 | template<class T, class U, class Base> |
| 364 | struct concept_interface<less_than_comparable<T, U>, Base, T> : Base |
| 365 | { |
| 366 | friend bool operator<(const typename derived<Base>::type& lhs, |
| 367 | typename as_param<Base, const U&>::type rhs) |
| 368 | { |
| 369 | return ::boost::type_erasure::call(less_than_comparable<T, U>(), lhs, rhs); |
| 370 | } |
| 371 | friend bool operator>=(const typename derived<Base>::type& lhs, |
| 372 | typename as_param<Base, const U&>::type rhs) |
| 373 | { |
| 374 | return !(lhs < rhs); |
| 375 | } |
| 376 | friend bool operator>(typename as_param<Base, const U&>::type lhs, |
| 377 | const typename derived<Base>::type& rhs) |
| 378 | { |
| 379 | return rhs < lhs; |
| 380 | } |
| 381 | friend bool operator<=(typename as_param<Base, const U&>::type lhs, |
| 382 | const typename derived<Base>::type& rhs) |
| 383 | { |
| 384 | return !(rhs < lhs); |
| 385 | } |
| 386 | }; |
| 387 | |
| 388 | template<class T, class U, class Base> |
| 389 | struct concept_interface< |
| 390 | less_than_comparable<T, U>, |
| 391 | Base, |
| 392 | U, |
| 393 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<T> >::type |
| 394 | > : Base |
| 395 | { |
| 396 | friend bool operator<(const T& lhs, const typename derived<Base>::type& rhs) |
| 397 | { |
| 398 | return ::boost::type_erasure::call(less_than_comparable<T, U>(), lhs, rhs); |
| 399 | } |
| 400 | friend bool operator>=(const T& lhs, const typename derived<Base>::type& rhs) |
| 401 | { |
| 402 | return !(lhs < rhs); |
| 403 | } |
| 404 | friend bool operator>(const typename derived<Base>::type& lhs, const T& rhs) |
| 405 | { |
| 406 | return rhs < lhs; |
| 407 | } |
| 408 | friend bool operator<=(const typename derived<Base>::type& lhs, const T& rhs) |
| 409 | { |
| 410 | return !(rhs < lhs); |
| 411 | } |
| 412 | }; |
| 413 | |
| 414 | /// \endcond |
| 415 | |
| 416 | template<class R, class T = _self, class N = std::ptrdiff_t> |
| 417 | struct subscriptable |
| 418 | { |
| 419 | static R apply(T& arg, const N& index) { return arg[index]; } |
| 420 | }; |
| 421 | |
| 422 | /// \cond show_operators |
| 423 | |
| 424 | template<class R, class T, class N, class Base> |
| 425 | struct concept_interface<subscriptable<R, T, N>, Base, typename ::boost::remove_const<T>::type, |
| 426 | typename ::boost::enable_if< |
| 427 | ::boost::type_erasure::detail::should_be_non_const<T, Base> |
| 428 | >::type |
| 429 | > : Base |
| 430 | { |
| 431 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator[]( |
| 432 | typename ::boost::type_erasure::as_param<Base, const N&>::type index) |
| 433 | { |
| 434 | return ::boost::type_erasure::call(subscriptable<R, T, N>(), *this, index); |
| 435 | } |
| 436 | }; |
| 437 | |
| 438 | template<class R, class T, class N, class Base> |
| 439 | struct concept_interface<subscriptable<R, T, N>, Base, typename ::boost::remove_const<T>::type, |
| 440 | typename ::boost::enable_if< |
| 441 | ::boost::type_erasure::detail::should_be_const<T, Base> |
| 442 | >::type |
| 443 | > : Base |
| 444 | { |
| 445 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator[]( |
| 446 | typename ::boost::type_erasure::as_param<Base, const N&>::type index) const |
| 447 | { |
| 448 | return ::boost::type_erasure::call(subscriptable<R, const T, N>(), *this, index); |
| 449 | } |
| 450 | }; |
| 451 | |
| 452 | /// \endcond |
| 453 | |
| 454 | /** |
| 455 | * The @ref ostreamable concept allows an @ref any to be |
| 456 | * written to a @c std::ostream. |
| 457 | */ |
| 458 | template<class Os = std::ostream, class T = _self> |
| 459 | struct ostreamable |
| 460 | { |
| 461 | static void apply(Os& out, const T& arg) { out << arg; } |
| 462 | }; |
| 463 | |
| 464 | /// \cond show_operators |
| 465 | |
| 466 | template<class Base, class Os, class T> |
| 467 | struct concept_interface<ostreamable<Os, T>, Base, Os> : Base |
| 468 | { |
| 469 | friend typename detail::non_const_this_param<Base>::type& |
| 470 | operator<<(typename detail::non_const_this_param<Base>::type& lhs, |
| 471 | typename ::boost::type_erasure::as_param<Base, const T&>::type rhs) |
| 472 | { |
| 473 | ::boost::type_erasure::call(ostreamable<Os, T>(), lhs, rhs); |
| 474 | return lhs; |
| 475 | } |
| 476 | }; |
| 477 | |
| 478 | template<class Base, class Os, class T> |
| 479 | struct concept_interface< |
| 480 | ostreamable<Os, T>, |
| 481 | Base, |
| 482 | T, |
| 483 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<Os> >::type |
| 484 | > : Base |
| 485 | { |
| 486 | friend Os& |
| 487 | operator<<(Os& lhs, |
| 488 | const typename ::boost::type_erasure::derived<Base>::type& rhs) |
| 489 | { |
| 490 | ::boost::type_erasure::call(ostreamable<Os, T>(), lhs, rhs); |
| 491 | return lhs; |
| 492 | } |
| 493 | }; |
| 494 | |
| 495 | /// \endcond |
| 496 | |
| 497 | /** |
| 498 | * The @ref istreamable concept allows an @ref any to be |
| 499 | * read from a @c std::istream. |
| 500 | */ |
| 501 | template<class Is = std::istream, class T = _self> |
| 502 | struct istreamable |
| 503 | { |
| 504 | static void apply(Is& out, T& arg) { out >> arg; } |
| 505 | }; |
| 506 | |
| 507 | /// \cond show_operators |
| 508 | |
| 509 | |
| 510 | template<class Base, class Is, class T> |
| 511 | struct concept_interface<istreamable<Is, T>, Base, Is> : Base |
| 512 | { |
| 513 | friend typename detail::non_const_this_param<Base>::type& |
| 514 | operator>>(typename detail::non_const_this_param<Base>::type& lhs, |
| 515 | typename ::boost::type_erasure::as_param<Base, T&>::type rhs) |
| 516 | { |
| 517 | ::boost::type_erasure::call(istreamable<Is, T>(), lhs, rhs); |
| 518 | return lhs; |
| 519 | } |
| 520 | }; |
| 521 | |
| 522 | template<class Base, class Is, class T> |
| 523 | struct concept_interface< |
| 524 | istreamable<Is, T>, |
| 525 | Base, |
| 526 | T, |
| 527 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<Is> >::type |
| 528 | > : Base |
| 529 | { |
| 530 | friend Is& |
| 531 | operator>>(Is& lhs, |
| 532 | typename ::boost::type_erasure::derived<Base>::type& rhs) |
| 533 | { |
| 534 | ::boost::type_erasure::call(istreamable<Is, T>(), lhs, rhs); |
| 535 | return lhs; |
| 536 | } |
| 537 | }; |
| 538 | |
| 539 | /// \endcond |
| 540 | |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | #endif |
| 545 | |