#ifndef SPROUT_TUPLE_TUPLE_HPP #define SPROUT_TUPLE_TUPLE_HPP #include #include #include #include #include #include namespace sprout { namespace tuples { namespace detail { template class head_base; template class head_base : public Head { public: static SPROUT_CONSTEXPR Head& head(head_base& t) SPROUT_NOEXCEPT { return t; } static SPROUT_CONSTEXPR Head const& head(head_base const& t) SPROUT_NOEXCEPT { return t; } public: SPROUT_CONSTEXPR head_base() : Head() {} SPROUT_CONSTEXPR head_base(Head const& v) : Head(v) {} template SPROUT_CONSTEXPR head_base(UHead&& v) : Head(sprout::forward(v)) {} }; template class head_base { public: static SPROUT_CONSTEXPR Head& head(head_base& t) SPROUT_NOEXCEPT { return t.head_; } static SPROUT_CONSTEXPR Head const& head(head_base const& t) SPROUT_NOEXCEPT { return t.head_; } private: Head head_; public: SPROUT_CONSTEXPR head_base() : head_() {} SPROUT_CONSTEXPR head_base(Head const& v) : head_(v) {} template SPROUT_CONSTEXPR head_base(UHead&& v) : head_(sprout::forward(v)) {} }; template class tuple_impl; template class tuple_impl { public: template friend class sprout::tuples::detail::tuple_impl; protected: void swap(tuple_impl&) SPROUT_NOEXCEPT {} public: tuple_impl() = default; template SPROUT_CONSTEXPR explicit tuple_impl(UTypes&&... args) SPROUT_NOEXCEPT {} SPROUT_CONSTEXPR tuple_impl(tuple_impl const&) = default; SPROUT_CONSTEXPR tuple_impl(tuple_impl&&) = default; template SPROUT_CONSTEXPR tuple_impl(tuple_impl const& t) SPROUT_NOEXCEPT {} template SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) SPROUT_NOEXCEPT {} tuple_impl& operator=(tuple_impl const&) = default; tuple_impl& operator=(tuple_impl&& t) = default; template tuple_impl& operator=(sprout::tuples::detail::tuple_impl const&) SPROUT_NOEXCEPT { return *this; } template tuple_impl& operator=(sprout::tuples::detail::tuple_impl&&) SPROUT_NOEXCEPT { return *this; } }; template class tuple_impl : public sprout::tuples::detail::tuple_impl , private sprout::tuples::detail::head_base::value> { public: template friend class sprout::tuples::detail::tuple_impl; public: typedef sprout::tuples::detail::tuple_impl inherited_type; typedef sprout::tuples::detail::head_base::value> base_type; public: static SPROUT_CONSTEXPR Head& head(tuple_impl& t) SPROUT_NOEXCEPT { return base_type::head(t); } static SPROUT_CONSTEXPR Head const& head(tuple_impl const& t) SPROUT_NOEXCEPT { return base_type::head(t); } static SPROUT_CONSTEXPR inherited_type& tail(tuple_impl& t) SPROUT_NOEXCEPT { return t; } static SPROUT_CONSTEXPR inherited_type const& tail(tuple_impl const& t) SPROUT_NOEXCEPT { return t; } protected: void swap(tuple_impl& t) SPROUT_NOEXCEPT_EXPR( SPROUT_NOEXCEPT_EXPR(swap(std::declval(), std::declval())) && SPROUT_NOEXCEPT_EXPR(tail(t).swap(tail(t))) ) { using std::swap; swap(head(*this), head(t)); inherited_type::swap(tail(t)); } public: SPROUT_CONSTEXPR tuple_impl() : inherited_type() , base_type() {} SPROUT_CONSTEXPR explicit tuple_impl(const Head& h, Tail const&... tail) : inherited_type(tail...) , base_type(h) {} template SPROUT_CONSTEXPR explicit tuple_impl(UHead&& h, UTail&&... tail) : inherited_type(sprout::forward(tail)...) , base_type(sprout::forward(h)) {} SPROUT_CONSTEXPR tuple_impl(tuple_impl const&) = default; SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_constructible::value && std::is_nothrow_move_constructible::value) : inherited_type(sprout::move(tail(t))) , base_type(sprout::forward(head(t))) {} template SPROUT_CONSTEXPR tuple_impl(tuple_impl const& t) : inherited_type(sprout::tuples::detail::tuple_impl::tail(t)) , base_type(sprout::tuples::detail::tuple_impl::head(t)) {} template SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) : inherited_type(sprout::move(sprout::tuples::detail::tuple_impl::tail(t))) , base_type(sprout::forward(sprout::tuples::detail::tuple_impl::head(t))) {} SPROUT_CONSTEXPR tuple_impl(tuple_impl const& t) : inherited_type() , base_type() {} SPROUT_CONSTEXPR tuple_impl(tuple_impl&& t) : inherited_type() , base_type() {} tuple_impl& operator=(tuple_impl const& t) { head(*this) = head(t); tail(*this) = tail(t); return *this; } tuple_impl& operator=(tuple_impl&& t) SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_assignable::value && std::is_nothrow_move_assignable::value) { head(*this) = sprout::forward(head(t)); tail(*this) = sprout::move(tail(t)); return *this; } template tuple_impl& operator=(sprout::tuples::detail::tuple_impl const& t) { head(*this) = sprout::tuples::detail::tuple_impl::head(t); tail(*this) = sprout::tuples::detail::tuple_impl::tail(t); return *this; } template tuple_impl& operator=(sprout::tuples::detail::tuple_impl&& t) { head(*this) = sprout::forward(sprout::tuples::detail::tuple_impl::head(t)); tail(*this) = sprout::move(sprout::tuples::detail::tuple_impl::tail(t)); return *this; } tuple_impl& operator=(sprout::tuples::detail::tuple_impl const& t) { *this = sprout::move(tuple_impl()); return *this; } tuple_impl& operator=(sprout::tuples::detail::tuple_impl&& t) { *this = sprout::move(tuple_impl()); return *this; } }; } // namespace detail // // tuple // template class tuple : public sprout::tuples::detail::tuple_impl<0, Types...> { public: typedef sprout::tuples::detail::tuple_impl<0, Types...> inherited_type; public: // tuple construction SPROUT_CONSTEXPR tuple() : inherited_type() {} SPROUT_CONSTEXPR explicit tuple(Types const&... elements) : inherited_type(elements...) {} template SPROUT_CONSTEXPR explicit tuple(UTypes&&... elements) : inherited_type(sprout::forward(elements)...) {} SPROUT_CONSTEXPR tuple(tuple const &) = default; SPROUT_CONSTEXPR tuple(tuple&&) = default; template SPROUT_CONSTEXPR tuple(sprout::tuples::tuple const& t) : inherited_type(static_cast const&>(t)) {} template SPROUT_CONSTEXPR tuple(sprout::tuples::tuple&& t) : inherited_type(static_cast&&>(t)) {} // tuple assignment tuple& operator=(const tuple& rhs) { static_cast(*this) = rhs; return *this; } tuple& operator=(tuple&& rhs) SPROUT_NOEXCEPT_EXPR(std::is_nothrow_move_assignable::value) { static_cast(*this) = sprout::move(rhs); return *this; } template tuple& operator=(sprout::tuples::tuple const& rhs) { static_cast(*this) = rhs; return *this; } template tuple& operator=(sprout::tuples::tuple&& rhs) { static_cast(*this) = sprout::move(rhs); return *this; } // tuple swap void swap(tuple& other) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(other.swap(other))) { inherited_type::swap(other); } }; template<> class tuple<> { public: // tuple swap void swap(tuple&) SPROUT_NOEXCEPT {} }; // // ignore_t // struct ignore_t { template ignore_t const& operator=(T const&) const { return *this; } }; // // ignore // static SPROUT_CONSTEXPR ignore_t ignore{}; // // make_tuple // template SPROUT_CONSTEXPR inline sprout::tuples::tuple::type...> make_tuple(Types&&... args) { return sprout::tuples::tuple::type...>(sprout::forward(args)...); } // // forward_as_tuple // template SPROUT_CONSTEXPR inline sprout::tuples::tuple forward_as_tuple(Types&&... args) SPROUT_NOEXCEPT { return sprout::tuples::tuple(sprout::forward(args)...); } // // tie // template inline sprout::tuples::tuple tie(Types&... args) SPROUT_NOEXCEPT { return sprout::tuples::tuple(args...); } // // swap // template inline void swap( sprout::tuples::tuple& lhs, sprout::tuples::tuple& rhs ) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(lhs.swap(rhs))) { lhs.swap(rhs); } namespace detail { template struct tuple_element_impl; template struct tuple_element_impl<0, sprout::tuples::tuple > { public: typedef Head type; }; template struct tuple_element_impl > : public sprout::tuples::detail::tuple_element_impl > {}; } // namespace detail } // namespace tuples using sprout::tuples::tuple; using sprout::tuples::ignore; using sprout::tuples::make_tuple; using sprout::tuples::forward_as_tuple; using sprout::tuples::tie; using sprout::tuples::swap; } // namespace sprout namespace std { // // tuple_size // template struct tuple_size > : public std::integral_constant {}; // // tuple_element // template struct tuple_element > : public sprout::tuples::detail::tuple_element_impl > {}; } // namespace std namespace sprout { namespace tuples { // // tuple_size // template struct tuple_size : public std::tuple_size {}; // // tuple_element // template struct tuple_element : public std::tuple_element {}; // // get // template SPROUT_CONSTEXPR auto get( T&& t ) SPROUT_NOEXCEPT_EXPR(SPROUT_NOEXCEPT_EXPR(std::get(sprout::forward(t)))) -> decltype(std::get(sprout::forward(t))) { return std::get(sprout::forward(t)); } // // get // namespace detail { template SPROUT_CONSTEXPR typename std::add_lvalue_reference::type get_helper( sprout::tuples::detail::tuple_impl& t ) SPROUT_NOEXCEPT { return sprout::tuples::detail::tuple_impl::head(t); } template SPROUT_CONSTEXPR typename std::add_lvalue_reference::type>::type get_helper( sprout::tuples::detail::tuple_impl const& t ) SPROUT_NOEXCEPT { return sprout::tuples::detail::tuple_impl::head(t); } } // namespace detail template SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type& get( sprout::tuples::tuple& t ) SPROUT_NOEXCEPT { return sprout::tuples::detail::get_helper(t); } template SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type&& get( sprout::tuples::tuple&& t ) SPROUT_NOEXCEPT { return sprout::forward >::type&&>( sprout::tuples::get(t) ); } template SPROUT_CONSTEXPR typename sprout::tuples::tuple_element >::type const& get( sprout::tuples::tuple const& t ) SPROUT_NOEXCEPT { return sprout::tuples::detail::get_helper(t); } } // namespace tuples using sprout::tuples::tuple_size; using sprout::tuples::tuple_element; using sprout::tuples::get; } // namespace sprout #endif // #ifndef SPROUT_TUPLE_TUPLE_HPP