Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // type_traits.hpp
- #include <utility>
- #include <type_traits>
- template< typename first, typename ...rest >
- struct identity
- {
- using type = first;
- };
- enum class type_qualifier
- {
- value,
- lref,
- rref,
- const_value,
- const_lref,
- const_rref,
- volatile_value,
- volatile_lref,
- volatile_rref,
- volatile_const_value,
- volatile_const_lref,
- volatile_const_rref,
- count_
- };
- template< type_qualifier type_qualifier, typename type > struct add_type_qualifier;
- template< typename to > struct add_type_qualifier< type_qualifier::value , to > { using type = to ; };
- template< typename to > struct add_type_qualifier< type_qualifier::lref , to > { using type = to & ; };
- template< typename to > struct add_type_qualifier< type_qualifier::rref , to > { using type = to &&; };
- template< typename to > struct add_type_qualifier< type_qualifier::const_value , to > { using type = to const ; };
- template< typename to > struct add_type_qualifier< type_qualifier::const_lref , to > { using type = to const & ; };
- template< typename to > struct add_type_qualifier< type_qualifier::const_rref , to > { using type = to const &&; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_value , to > { using type = volatile to ; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_lref , to > { using type = volatile to & ; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_rref , to > { using type = volatile to &&; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_value , to > { using type = volatile to const ; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_lref , to > { using type = volatile to const & ; };
- template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_rref , to > { using type = volatile to const &&; };
- template< type_qualifier type_qualifier, typename to >
- using add_qualifier_t = typename add_type_qualifier< type_qualifier, to >::type;
- template< typename type > constexpr type_qualifier type_qualifier_of = type_qualifier::value ;
- template< typename type > constexpr type_qualifier type_qualifier_of< type & > = type_qualifier::lref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< type && > = type_qualifier::rref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< type const > = type_qualifier::const_value ;
- template< typename type > constexpr type_qualifier type_qualifier_of< type const & > = type_qualifier::const_lref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< type const && > = type_qualifier::const_rref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type > = type_qualifier::volatile_value ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type & > = type_qualifier::volatile_lref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type && > = type_qualifier::volatile_rref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const > = type_qualifier::volatile_const_value ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const & > = type_qualifier::volatile_const_lref ;
- template< typename type > constexpr type_qualifier type_qualifier_of< volatile type const && > = type_qualifier::volatile_const_rref ;
- template< typename from, typename to >
- using copy_cv_reference_t = add_qualifier_t< type_qualifier_of< from >, to >;
- // visit.hpp
- #include <cstddef>
- #include <cassert>
- namespace details
- {
- template< typename visitor, typename visitable, typename visitable_type = std::decay_t< visitable > >
- struct dispatcher;
- template< typename visitor, typename visitable,
- template< typename ...types > class visitable_type, typename ...types >
- struct dispatcher< visitor, visitable, visitable_type< types... > >
- {
- template< typename ...arguments >
- static
- constexpr
- decltype(auto)
- call(visitor & _visitor, visitable & _visitable, arguments &... _arguments)
- {
- assert(!(sizeof...(types) < static_cast< std::size_t >(_visitable.which())));
- return callers_< arguments... >[sizeof...(types) - _visitable.which()](_visitor, _visitable, _arguments...);
- }
- private :
- template< typename type, typename ...arguments >
- static
- constexpr
- decltype(auto)
- caller(visitor & _visitor, visitable & _visitable, arguments &... _arguments)
- {
- return std::forward< visitor >(_visitor)(static_cast< type >(static_cast< type & >(_visitable)), std::forward< arguments >(_arguments)...);
- }
- static constexpr type_qualifier type_qualifier_ = type_qualifier_of< visitable && >;
- template< typename type >
- using qualify_type_t = add_qualifier_t< type_qualifier_, std::decay_t< type > >;
- template< typename ...arguments >
- using caller_type = decltype(&dispatcher::template caller< qualify_type_t< typename identity< types... >::type >, arguments... >);
- template< typename ...arguments >
- static constexpr caller_type< arguments... > callers_[sizeof...(types)] = {dispatcher::template caller< qualify_type_t< types >, arguments... >...};
- };
- template< typename visitor, typename visitable,
- template< typename ...types > class visitable_type, typename ...types >
- template< typename ...arguments >
- constexpr typename dispatcher< visitor, visitable, visitable_type< types... > >::template caller_type< arguments... > dispatcher< visitor, visitable, visitable_type< types... > >::callers_[sizeof...(types)];
- }
- template< typename visitor, typename visitable, typename ...arguments >
- constexpr
- decltype(auto)
- visit(visitor && _visitor, visitable && _visitable, arguments &&... _arguments)
- {
- return details::template dispatcher< visitor, visitable >::template call< arguments... >(_visitor, _visitable, _arguments...);
- }
- // test.hpp
- #include <cstdlib>
- template< typename first, typename second, typename third >
- struct variant3
- {
- constexpr variant3(first) : which_{3} { ; }
- constexpr variant3(second) : which_{2} { ; }
- constexpr variant3(third) : which_{1} { ; }
- constexpr std::size_t which() const { return which_; }
- constexpr operator first const & () const { return first_; }
- constexpr operator second const & () const { return second_; }
- constexpr operator third const & () const { return third_; }
- constexpr operator first & () { return first_; }
- constexpr operator second & () { return second_; }
- constexpr operator third & () { return third_; }
- private :
- std::size_t which_;
- first first_;
- second second_;
- third third_;
- };
- struct A {};
- struct B {};
- struct C {};
- using V = variant3< A, B, C >;
- static_assert(std::is_literal_type< V >{});
- struct visitor3
- {
- constexpr auto operator () (A, int i = 1) { return 100 + i; }
- constexpr auto operator () (B, int i = 2) { return 200 + i; }
- constexpr auto operator () (C, int i = 3) { return 300 + i; }
- };
- static_assert(std::is_literal_type< visitor3 >{});
- namespace test
- {
- static_assert(visit(visitor3{}, V{A{}}) == 101);
- static_assert(visit(visitor3{}, V{B{}}) == 202);
- static_assert(visit(visitor3{}, V{C{}}) == 303);
- static_assert(visit(visitor3{}, V{A{}}, 10) == 110);
- static_assert(visit(visitor3{}, V{B{}}, 20) == 220);
- static_assert(visit(visitor3{}, V{C{}}, 30) == 330);
- }
Advertisement
Add Comment
Please, Sign In to add comment