Header file range/v3/utility/tagged_pair.hpp

#include <meta/meta.hpp>

#include <range/v3/range_fwd.hpp>

#include <range/v3/utility/concepts.hpp>

#include <range/v3/utility/swap.hpp>

#define RANGES_DEFINE_TAG_SPECIFIER(NAME) namespace tag                                                                        {                                                                                        struct NAME                                                                          {                                                                                        template<typename Untagged, std::size_t I, typename Next>                            class getter : public Next                                                           {                                                                                    protected:                                                                               ~getter() = default;                                                             public:                                                                                  getter() = default;                                                                  getter(getter &&) = default;                                                         getter(getter const &) = default;                                                    using Next::Next;                                                                    CONCEPT_REQUIRES(MoveConstructible<Untagged>())                                      constexpr getter(Untagged && that)                                                       noexcept(std::is_nothrow_move_constructible<Untagged>::value)                      : Next(detail::move(that))                                                         {}                                                                                   CONCEPT_REQUIRES(CopyConstructible<Untagged>())                                      constexpr getter(Untagged const &that)                                                   noexcept(std::is_nothrow_copy_constructible<Untagged>::value)                      : Next(that)                                                                       {}                                                                                   getter &operator=(getter &&) = default;                                              getter &operator=(getter const &) = default;                                         RANGES_CXX14_CONSTEXPR                                                               meta::_t<std::tuple_element<I, Untagged>> &NAME() &                                      noexcept(noexcept(                                                                       detail::adl_get<I>(std::declval<Untagged &>())))                             {                                                                                        return detail::adl_get<I>(static_cast<Untagged &>(*this));                       }                                                                                    RANGES_CXX14_CONSTEXPR                                                               meta::_t<std::tuple_element<I, Untagged>> &&NAME() &&                                    noexcept(noexcept(                                                                       detail::adl_get<I>(std::declval<Untagged>())))                               {                                                                                        return detail::adl_get<I>(static_cast<Untagged &&>(*this));                      }                                                                                    constexpr                                                                            meta::_t<std::tuple_element<I, Untagged>> const &NAME() const &                          noexcept(noexcept(                                                                       detail::adl_get<I>(std::declval<Untagged const &>())))                       {                                                                                        return detail::adl_get<I>(static_cast<Untagged const &>(*this));                 }                                                                                };                                                                               };                                                                               }

namespace ranges
{
    inline namespace v3
    {
        namespace detail
        {
            template <typename T>
            using tag_spec = meta::front<meta::as_list<T>>;
            
            template <typename T>
            using tag_elem = meta::back<meta::as_list<T>>;
            
            namespace adl_get_detail
            {
                using std::get;
                
                template <std::size_t I, typename T>
                constexpr decltype(get<I>((T&&)t)) adl_get(T&& t) noexcept(noexcept(decltype(get<I>((T&&)t))(get<I>((T&&)t))));
            }
            
            using adl_get_detail::adl_get;
        }
        
        namespace tagged_detail
        {
            template <typename Base, std::size_t, typename>
            struct chain;
            
            template <typename Base, std::size_t I, typename First, typename ... Rest>
            struct chain<Base, I, First, Rest...>
            {
                using type = typename First::template getter<Base, I, meta::_t<chain<Base, I+1, Rest...>>>;
            };
            
            template <typename Base, typename ... Tags>
            class tagged
            : public meta::_t<chain<Base, 0, Tags...> >
            {
            public:
                tagged() = default;
                
                using base_t::base_t;
                
                template <int _concept_requires_81 = 42, typename std::enable_if<(_concept_requires_81==43)||(MoveConstructible<Base>()), int>::type=0>
                constexpr tagged(Base&& that) noexcept(std::is_nothrow_move_constructible<Base>::value);
                
                template <int _concept_requires_86 = 42, typename std::enable_if<(_concept_requires_86==43)||(CopyConstructible<Base>()), int>::type=0>
                constexpr tagged(Base const& that) noexcept(std::is_nothrow_copy_constructible<Base>::value);
                
                template <typename Other, typename = meta::if_<can_convert<Other>>>
                constexpr tagged(tagged<Other, Tags...>&& that) noexcept(std::is_nothrow_constructible<Base, Other>::value);
                
                template <typename Other, typename = meta::if_<can_convert<Other>>>
                constexpr tagged(tagged<Other, Tags...>const& that) noexcept(std::is_nothrow_constructible<Base, Other const&>::value);
                
                template <typename Other, typename = meta::if_<can_convert<Other>>>
                constexpr tagged& operator=(tagged<Other, Tags...>&& that) noexcept(noexcept(std::declval<Base&>()=static_cast<Other&&>(that)));
                
                template <typename Other, typename = meta::if_<can_convert<Other>>>
                constexpr tagged& operator=(tagged<Other, Tags...>const& that) noexcept(noexcept(std::declval<Base&>()=static_cast<Other const&>(that)));
                
                template <typename U, typename = meta::if_c<!std::is_same<tagged, detail::decay_t<U>>::value>, typename = decltype(std::declval<Base&>()=std::declval<U>())>
                constexpr )>tagged& operator=(U&& u) noexcept(noexcept(std::declval<Base&>()=std::forward<U>(u)));
                
                template <int dummy_ = 42>
                constexpr meta::if_c<dummy_==43||is_swappable<Base&>::value> swap(tagged& that) noexcept(is_nothrow_swappable<Base&>::value);
            };
        }
        
        using tagged_detail::tagged;
        
        template <typename F, typename S>
        using tagged_pair = tagged<std::pair<detail::tag_elem<F>, detail::tag_elem<S>>, detail::tag_spec<F>, detail::tag_spec<S>>;
        
        template <typename Tag1, typename Tag2, typename T1, typename T2, typename R = tagged_pair<Tag1(bind_element_t<T1>), Tag2(bind_element_t<T2>)>>
        constexpr R make_tagged_pair(T1&& t1, T2&& t2) noexcept(std::is_nothrow_constructible<R, T1, T2>::value);
    }
}

namespace std{}