|
18 | 18 | // Library version |
19 | 19 |
|
20 | 20 | #define VISIT_STRUCT_VERSION_MAJOR 1 |
21 | | -#define VISIT_STRUCT_VERSION_MINOR 1 |
22 | | -#define VISIT_STRUCT_VERSION_PATCH 2 |
| 21 | +#define VISIT_STRUCT_VERSION_MINOR 2 |
| 22 | +#define VISIT_STRUCT_VERSION_PATCH 0 |
23 | 23 |
|
24 | 24 | #define VISIT_STRUCT_STRING_HELPER(X) #X |
25 | 25 | #define VISIT_STRUCT_STRING(X) VISIT_STRUCT_STRING_HELPER(X) |
@@ -61,16 +61,19 @@ namespace visit_struct { |
61 | 61 | namespace traits { |
62 | 62 |
|
63 | 63 | // Primary template which is specialized to register a type |
64 | | -template <typename T, typename ENABLE = void> |
| 64 | +// The context parameter is set when a user wants to register multiple visitation patterns, |
| 65 | +// to include or exclude some field in different contexts. |
| 66 | +template <typename T, typename CONTEXT = void> |
65 | 67 | struct visitable; |
66 | 68 |
|
67 | 69 | // Helper template which checks if a type is registered |
68 | | -template <typename T, typename ENABLE = void> |
| 70 | +template <typename T, typename CONTEXT = void, typename ENABLE = void> |
69 | 71 | struct is_visitable : std::false_type {}; |
70 | 72 |
|
71 | | -template <typename T> |
| 73 | +template <typename T, typename CONTEXT> |
72 | 74 | struct is_visitable<T, |
73 | | - typename std::enable_if<traits::visitable<T>::value>::type> |
| 75 | + CONTEXT, |
| 76 | + typename std::enable_if<traits::visitable<T, CONTEXT>::value>::type> |
74 | 77 | : std::true_type {}; |
75 | 78 |
|
76 | 79 | // Helper template which removes cv and reference from a type (saves some typing) |
@@ -298,6 +301,204 @@ VISIT_STRUCT_CONSTEXPR auto get_name(S &&) -> decltype(get_name<S>()) { |
298 | 301 | return get_name<S>(); |
299 | 302 | } |
300 | 303 |
|
| 304 | +// Alternate visitation patterns can be registered using VISITABLE_STRUCT_IN_CONTEXT. |
| 305 | +// Then, use visit_struct::context<C>::for_each and similar to refer to special contexts. |
| 306 | +template <typename CONTEXT> |
| 307 | +struct context { |
| 308 | + |
| 309 | + // Return number of fields in a visitable struct |
| 310 | + template <typename S> |
| 311 | + VISIT_STRUCT_CONSTEXPR static std::size_t field_count() |
| 312 | + { |
| 313 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::field_count; |
| 314 | + } |
| 315 | + |
| 316 | + template <typename S> |
| 317 | + VISIT_STRUCT_CONSTEXPR static std::size_t field_count(S &&) { return field_count<S>(); } |
| 318 | + |
| 319 | + |
| 320 | + // apply_visitor (one struct instance) |
| 321 | + template <typename S, typename V> |
| 322 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto apply_visitor(V && v, S && s) -> |
| 323 | + typename std::enable_if< |
| 324 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 325 | + >::type |
| 326 | + { |
| 327 | + traits::visitable<traits::clean_t<S>, CONTEXT>::apply(std::forward<V>(v), std::forward<S>(s)); |
| 328 | + } |
| 329 | + |
| 330 | + // apply_visitor (two struct instances) |
| 331 | + template <typename S1, typename S2, typename V> |
| 332 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto apply_visitor(V && v, S1 && s1, S2 && s2) -> |
| 333 | + typename std::enable_if< |
| 334 | + traits::is_visitable< |
| 335 | + traits::clean_t<typename traits::common_type<S1, S2>::type>, |
| 336 | + CONTEXT |
| 337 | + >::value |
| 338 | + >::type |
| 339 | + { |
| 340 | + using common_S = typename traits::common_type<S1, S2>::type; |
| 341 | + traits::visitable<traits::clean_t<common_S>, CONTEXT>::apply(std::forward<V>(v), |
| 342 | + std::forward<S1>(s1), |
| 343 | + std::forward<S2>(s2)); |
| 344 | + } |
| 345 | + |
| 346 | + // for_each (Alternate syntax for apply_visitor, reverses order of arguments) |
| 347 | + template <typename V, typename S> |
| 348 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto for_each(S && s, V && v) -> |
| 349 | + typename std::enable_if< |
| 350 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 351 | + >::type |
| 352 | + { |
| 353 | + traits::visitable<traits::clean_t<S>, CONTEXT>::apply(std::forward<V>(v), std::forward<S>(s)); |
| 354 | + } |
| 355 | + |
| 356 | + // for_each with two structure instances |
| 357 | + template <typename S1, typename S2, typename V> |
| 358 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto for_each(S1 && s1, S2 && s2, V && v) -> |
| 359 | + typename std::enable_if< |
| 360 | + traits::is_visitable< |
| 361 | + traits::clean_t<typename traits::common_type<S1, S2>::type>, |
| 362 | + CONTEXT |
| 363 | + >::value |
| 364 | + >::type |
| 365 | + { |
| 366 | + using common_S = typename traits::common_type<S1, S2>::type; |
| 367 | + traits::visitable<traits::clean_t<common_S>, CONTEXT>::apply(std::forward<V>(v), |
| 368 | + std::forward<S1>(s1), |
| 369 | + std::forward<S2>(s2)); |
| 370 | + } |
| 371 | + |
| 372 | + // Visit the types (visit_struct::type_c<...>) of the registered members |
| 373 | + template <typename S, typename V> |
| 374 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto visit_types(V && v) -> |
| 375 | + typename std::enable_if< |
| 376 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 377 | + >::type |
| 378 | + { |
| 379 | + traits::visitable<traits::clean_t<S>, CONTEXT>::visit_types(std::forward<V>(v)); |
| 380 | + } |
| 381 | + |
| 382 | + // Visit the member pointers (&S::a) of the registered members |
| 383 | + template <typename S, typename V> |
| 384 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto visit_pointers(V && v) -> |
| 385 | + typename std::enable_if< |
| 386 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 387 | + >::type |
| 388 | + { |
| 389 | + traits::visitable<traits::clean_t<S>, CONTEXT>::visit_pointers(std::forward<V>(v)); |
| 390 | + } |
| 391 | + |
| 392 | + // Visit the accessors (function objects) of the registered members |
| 393 | + template <typename S, typename V> |
| 394 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto visit_accessors(V && v) -> |
| 395 | + typename std::enable_if< |
| 396 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 397 | + >::type |
| 398 | + { |
| 399 | + traits::visitable<traits::clean_t<S>, CONTEXT>::visit_accessors(std::forward<V>(v)); |
| 400 | + } |
| 401 | + |
| 402 | + |
| 403 | + // Apply visitor (with no instances) |
| 404 | + // This calls visit_pointers, for backwards compat reasons |
| 405 | + template <typename S, typename V> |
| 406 | + VISIT_STRUCT_CXX14_CONSTEXPR static auto apply_visitor(V && v) -> |
| 407 | + typename std::enable_if< |
| 408 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value |
| 409 | + >::type |
| 410 | + { |
| 411 | + visit_struct::visit_pointers<S>(std::forward<V>(v)); |
| 412 | + } |
| 413 | + |
| 414 | + |
| 415 | + // Get value by index (like std::get for tuples) |
| 416 | + template <int idx, typename S> |
| 417 | + VISIT_STRUCT_CONSTEXPR static auto get(S && s) -> |
| 418 | + typename std::enable_if< |
| 419 | + traits::is_visitable<traits::clean_t<S>>::value, |
| 420 | + decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::get_value(std::integral_constant<int, idx>{}, std::forward<S>(s))) |
| 421 | + >::type |
| 422 | + { |
| 423 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::get_value(std::integral_constant<int, idx>{}, std::forward<S>(s)); |
| 424 | + } |
| 425 | + |
| 426 | + // Get name of field, by index |
| 427 | + template <int idx, typename S> |
| 428 | + VISIT_STRUCT_CONSTEXPR static auto get_name() -> |
| 429 | + typename std::enable_if< |
| 430 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value, |
| 431 | + decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::get_name(std::integral_constant<int, idx>{})) |
| 432 | + >::type |
| 433 | + { |
| 434 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::get_name(std::integral_constant<int, idx>{}); |
| 435 | + } |
| 436 | + |
| 437 | + template <int idx, typename S> |
| 438 | + VISIT_STRUCT_CONSTEXPR static auto get_name(S &&) -> decltype(get_name<idx, S>()) { |
| 439 | + return get_name<idx, S>(); |
| 440 | + } |
| 441 | + |
| 442 | + // Get member pointer, by index |
| 443 | + template <int idx, typename S> |
| 444 | + VISIT_STRUCT_CONSTEXPR static auto get_pointer() -> |
| 445 | + typename std::enable_if< |
| 446 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value, |
| 447 | + decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::get_pointer(std::integral_constant<int, idx>{})) |
| 448 | + >::type |
| 449 | + { |
| 450 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::get_pointer(std::integral_constant<int, idx>{}); |
| 451 | + } |
| 452 | + |
| 453 | + template <int idx, typename S> |
| 454 | + VISIT_STRUCT_CONSTEXPR static auto get_pointer(S &&) -> decltype(get_pointer<idx, S>()) { |
| 455 | + return get_pointer<idx, S>(); |
| 456 | + } |
| 457 | + |
| 458 | + // Get member accessor, by index |
| 459 | + template <int idx, typename S> |
| 460 | + VISIT_STRUCT_CONSTEXPR static auto get_accessor() -> |
| 461 | + typename std::enable_if< |
| 462 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value, |
| 463 | + decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::get_accessor(std::integral_constant<int, idx>{})) |
| 464 | + >::type |
| 465 | + { |
| 466 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::get_accessor(std::integral_constant<int, idx>{}); |
| 467 | + } |
| 468 | + |
| 469 | + template <int idx, typename S> |
| 470 | + VISIT_STRUCT_CONSTEXPR static auto get_accessor(S &&) -> decltype(get_accessor<idx, S>()) { |
| 471 | + return get_accessor<idx, S>(); |
| 472 | + } |
| 473 | + |
| 474 | + // Get type, by index |
| 475 | + template <int idx, typename S> |
| 476 | + struct type_at_s { |
| 477 | + using type_c = decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::type_at(std::integral_constant<int, idx>{})); |
| 478 | + using type = typename type_c::type; |
| 479 | + }; |
| 480 | + |
| 481 | + template <int idx, typename S> |
| 482 | + using type_at = typename type_at_s<idx, S>::type; |
| 483 | + |
| 484 | + // Get name of structure |
| 485 | + template <typename S> |
| 486 | + VISIT_STRUCT_CONSTEXPR static auto get_name() -> |
| 487 | + typename std::enable_if< |
| 488 | + traits::is_visitable<traits::clean_t<S>, CONTEXT>::value, |
| 489 | + decltype(traits::visitable<traits::clean_t<S>, CONTEXT>::get_name()) |
| 490 | + >::type |
| 491 | + { |
| 492 | + return traits::visitable<traits::clean_t<S>, CONTEXT>::get_name(); |
| 493 | + } |
| 494 | + |
| 495 | + template <typename S> |
| 496 | + VISIT_STRUCT_CONSTEXPR static auto get_name(S &&) -> decltype(get_name<S>()) { |
| 497 | + return get_name<S>(); |
| 498 | + } |
| 499 | +}; |
| 500 | + |
| 501 | + |
301 | 502 | /*** |
302 | 503 | * To implement the VISITABLE_STRUCT macro, we need a map-macro, which can take |
303 | 504 | * the name of a macro and some other arguments, and apply that macro to each other argument. |
@@ -561,6 +762,66 @@ struct visitable<STRUCT_NAME, void> { |
561 | 762 | } \ |
562 | 763 | static_assert(true, "") |
563 | 764 |
|
| 765 | +#define VISITABLE_STRUCT_IN_CONTEXT(CONTEXT, STRUCT_NAME, ...) \ |
| 766 | +namespace visit_struct { \ |
| 767 | +namespace traits { \ |
| 768 | + \ |
| 769 | +template <> \ |
| 770 | +struct visitable<STRUCT_NAME, CONTEXT> { \ |
| 771 | + \ |
| 772 | + using this_type = STRUCT_NAME; \ |
| 773 | + \ |
| 774 | + static VISIT_STRUCT_CONSTEXPR auto get_name() \ |
| 775 | + -> decltype(#STRUCT_NAME) { \ |
| 776 | + return #STRUCT_NAME; \ |
| 777 | + } \ |
| 778 | + \ |
| 779 | + static VISIT_STRUCT_CONSTEXPR const std::size_t field_count = 0 \ |
| 780 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_FIELD_COUNT, __VA_ARGS__); \ |
| 781 | + \ |
| 782 | + template <typename V, typename S> \ |
| 783 | + VISIT_STRUCT_CXX14_CONSTEXPR static void apply(V && visitor, S && struct_instance) \ |
| 784 | + { \ |
| 785 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MEMBER_HELPER, __VA_ARGS__) \ |
| 786 | + } \ |
| 787 | + \ |
| 788 | + template <typename V, typename S1, typename S2> \ |
| 789 | + VISIT_STRUCT_CXX14_CONSTEXPR static void apply(V && visitor, S1 && s1, S2 && s2) \ |
| 790 | + { \ |
| 791 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MEMBER_HELPER_PAIR, __VA_ARGS__) \ |
| 792 | + } \ |
| 793 | + \ |
| 794 | + template <typename V> \ |
| 795 | + VISIT_STRUCT_CXX14_CONSTEXPR static void visit_pointers(V && visitor) \ |
| 796 | + { \ |
| 797 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MEMBER_HELPER_PTR, __VA_ARGS__) \ |
| 798 | + } \ |
| 799 | + \ |
| 800 | + template <typename V> \ |
| 801 | + VISIT_STRUCT_CXX14_CONSTEXPR static void visit_types(V && visitor) \ |
| 802 | + { \ |
| 803 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MEMBER_HELPER_TYPE, __VA_ARGS__) \ |
| 804 | + } \ |
| 805 | + \ |
| 806 | + template <typename V> \ |
| 807 | + VISIT_STRUCT_CXX14_CONSTEXPR static void visit_accessors(V && visitor) \ |
| 808 | + { \ |
| 809 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MEMBER_HELPER_ACC, __VA_ARGS__) \ |
| 810 | + } \ |
| 811 | + \ |
| 812 | + struct fields_enum { \ |
| 813 | + enum index { __VA_ARGS__ }; \ |
| 814 | + }; \ |
| 815 | + \ |
| 816 | + VISIT_STRUCT_PP_MAP(VISIT_STRUCT_MAKE_GETTERS, __VA_ARGS__) \ |
| 817 | + \ |
| 818 | + static VISIT_STRUCT_CONSTEXPR const bool value = true; \ |
| 819 | +}; \ |
| 820 | + \ |
| 821 | +} \ |
| 822 | +} \ |
| 823 | +static_assert(true, "") |
| 824 | + |
564 | 825 | } // end namespace visit_struct |
565 | 826 |
|
566 | 827 | #endif // VISIT_STRUCT_HPP_INCLUDED |
0 commit comments