Dukales

constexpr visitation

Nov 13th, 2015
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.91 KB | None | 0 0
  1. // type_traits.hpp
  2. #include <utility>
  3. #include <type_traits>
  4.  
  5. template< typename first, typename ...rest >
  6. struct identity
  7. {
  8.  
  9.     using type = first;
  10.  
  11. };
  12.  
  13. enum class type_qualifier
  14. {
  15.     value,
  16.     lref,
  17.     rref,
  18.     const_value,
  19.     const_lref,
  20.     const_rref,
  21.     volatile_value,
  22.     volatile_lref,
  23.     volatile_rref,
  24.     volatile_const_value,
  25.     volatile_const_lref,
  26.     volatile_const_rref,
  27.  
  28.     count_
  29. };
  30.  
  31. template< type_qualifier type_qualifier, typename type > struct add_type_qualifier;
  32. template< typename to > struct add_type_qualifier< type_qualifier::value                , to > { using type =          to         ; };
  33. template< typename to > struct add_type_qualifier< type_qualifier::lref                 , to > { using type =          to       & ; };
  34. template< typename to > struct add_type_qualifier< type_qualifier::rref                 , to > { using type =          to       &&; };
  35. template< typename to > struct add_type_qualifier< type_qualifier::const_value          , to > { using type =          to const   ; };
  36. template< typename to > struct add_type_qualifier< type_qualifier::const_lref           , to > { using type =          to const & ; };
  37. template< typename to > struct add_type_qualifier< type_qualifier::const_rref           , to > { using type =          to const &&; };
  38. template< typename to > struct add_type_qualifier< type_qualifier::volatile_value       , to > { using type = volatile to         ; };
  39. template< typename to > struct add_type_qualifier< type_qualifier::volatile_lref        , to > { using type = volatile to       & ; };
  40. template< typename to > struct add_type_qualifier< type_qualifier::volatile_rref        , to > { using type = volatile to       &&; };
  41. template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_value , to > { using type = volatile to const   ; };
  42. template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_lref  , to > { using type = volatile to const & ; };
  43. template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_rref  , to > { using type = volatile to const &&; };
  44.  
  45. template< type_qualifier type_qualifier, typename to >
  46. using add_qualifier_t = typename add_type_qualifier< type_qualifier, to >::type;
  47.  
  48. template< typename type > constexpr type_qualifier type_qualifier_of                           = type_qualifier::value                ;
  49. template< typename type > constexpr type_qualifier type_qualifier_of<          type       &  > = type_qualifier::lref                 ;
  50. template< typename type > constexpr type_qualifier type_qualifier_of<          type       && > = type_qualifier::rref                 ;
  51. template< typename type > constexpr type_qualifier type_qualifier_of<          type const    > = type_qualifier::const_value          ;
  52. template< typename type > constexpr type_qualifier type_qualifier_of<          type const &  > = type_qualifier::const_lref           ;
  53. template< typename type > constexpr type_qualifier type_qualifier_of<          type const && > = type_qualifier::const_rref           ;
  54. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type          > = type_qualifier::volatile_value       ;
  55. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type       &  > = type_qualifier::volatile_lref        ;
  56. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type       && > = type_qualifier::volatile_rref        ;
  57. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const    > = type_qualifier::volatile_const_value ;
  58. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const &  > = type_qualifier::volatile_const_lref  ;
  59. template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const && > = type_qualifier::volatile_const_rref  ;
  60.  
  61. template< typename from, typename to >
  62. using copy_cv_reference_t = add_qualifier_t< type_qualifier_of< from >, to >;
  63.  
  64. // visit.hpp
  65. #include <cstddef>
  66. #include <cassert>
  67.  
  68. namespace details
  69. {
  70.  
  71. template< typename visitor, typename visitable, typename visitable_type = std::decay_t< visitable > >
  72. struct dispatcher;
  73.  
  74. template< typename visitor, typename visitable,
  75.           template< typename ...types > class visitable_type, typename ...types >
  76. struct dispatcher< visitor, visitable, visitable_type< types... > >
  77. {
  78.  
  79.     template< typename ...arguments >
  80.     static
  81.     constexpr
  82.     decltype(auto)
  83.     call(visitor & _visitor, visitable & _visitable, arguments &... _arguments)
  84.     {
  85.         assert(!(sizeof...(types) < static_cast< std::size_t >(_visitable.which())));
  86.         return callers_< arguments... >[sizeof...(types) - _visitable.which()](_visitor, _visitable, _arguments...);
  87.     }
  88.  
  89. private :
  90.  
  91.     template< typename type, typename ...arguments >
  92.     static
  93.     constexpr
  94.     decltype(auto)
  95.     caller(visitor & _visitor, visitable & _visitable, arguments &... _arguments)
  96.     {
  97.         return std::forward< visitor >(_visitor)(static_cast< type >(static_cast< type & >(_visitable)), std::forward< arguments >(_arguments)...);
  98.     }
  99.  
  100.     static constexpr type_qualifier type_qualifier_ = type_qualifier_of< visitable && >;
  101.  
  102.     template< typename type >
  103.     using qualify_type_t = add_qualifier_t< type_qualifier_, std::decay_t< type > >;
  104.  
  105.     template< typename ...arguments >
  106.     using caller_type = decltype(&dispatcher::template caller< qualify_type_t< typename identity< types... >::type >, arguments... >);
  107.     template< typename ...arguments >
  108.     static constexpr caller_type< arguments... > callers_[sizeof...(types)] = {dispatcher::template caller< qualify_type_t< types >, arguments... >...};
  109.  
  110. };
  111.  
  112. template< typename visitor, typename visitable,
  113.           template< typename ...types > class visitable_type, typename ...types >
  114. template< typename ...arguments >
  115. constexpr typename dispatcher< visitor, visitable, visitable_type< types... > >::template caller_type< arguments... > dispatcher< visitor, visitable, visitable_type< types... > >::callers_[sizeof...(types)];
  116.  
  117. }
  118.  
  119. template< typename visitor, typename visitable, typename ...arguments >
  120. constexpr
  121. decltype(auto)
  122. visit(visitor && _visitor, visitable && _visitable, arguments &&... _arguments)
  123. {
  124.     return details::template dispatcher< visitor, visitable >::template call< arguments... >(_visitor, _visitable, _arguments...);
  125. }
  126.  
  127. // test.hpp
  128. #include <cstdlib>
  129.  
  130. template< typename first, typename second, typename third >
  131. struct variant3
  132. {
  133.    
  134.     constexpr variant3(first)  : which_{3} { ; }
  135.     constexpr variant3(second) : which_{2} { ; }
  136.     constexpr variant3(third)  : which_{1} { ; }
  137.    
  138.     constexpr std::size_t which() const { return which_; }
  139.    
  140.     constexpr operator first const &  () const { return first_;  }
  141.     constexpr operator second const & () const { return second_; }
  142.     constexpr operator third const &  () const { return third_;  }
  143.    
  144.     constexpr operator first &  () { return first_;  }
  145.     constexpr operator second & () { return second_; }
  146.     constexpr operator third &  () { return third_;  }
  147.    
  148. private :
  149.  
  150.     std::size_t which_;
  151.  
  152.     first  first_;
  153.     second second_;
  154.     third  third_;
  155.    
  156. };
  157.  
  158. struct A {};
  159. struct B {};
  160. struct C {};
  161. using V = variant3< A, B, C >;
  162.  
  163. static_assert(std::is_literal_type< V >{});
  164.  
  165. struct visitor3
  166. {
  167.     constexpr auto operator () (A, int i = 1) { return 100 + i; }
  168.     constexpr auto operator () (B, int i = 2) { return 200 + i; }
  169.     constexpr auto operator () (C, int i = 3) { return 300 + i; }
  170. };
  171.  
  172. static_assert(std::is_literal_type< visitor3 >{});
  173.  
  174. namespace test
  175. {
  176.  
  177. static_assert(visit(visitor3{}, V{A{}}) == 101);
  178. static_assert(visit(visitor3{}, V{B{}}) == 202);
  179. static_assert(visit(visitor3{}, V{C{}}) == 303);
  180.  
  181. static_assert(visit(visitor3{}, V{A{}}, 10) == 110);
  182. static_assert(visit(visitor3{}, V{B{}}, 20) == 220);
  183. static_assert(visit(visitor3{}, V{C{}}, 30) == 330);
  184.  
  185. }
Advertisement
Add Comment
Please, Sign In to add comment