Last active
October 21, 2019 14:01
-
-
Save talybin/66cfa681ac82e13b26731b0d905c6c0d to your computer and use it in GitHub Desktop.
Basic implementation of tuple
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <utility> | |
| // Basic implementation of tuple | |
| template <class...> | |
| struct tuple; | |
| template <> | |
| struct tuple<> { }; | |
| template <class T, class... Ts> | |
| struct tuple<T, Ts...> : tuple<Ts...> | |
| { | |
| tuple() = default; | |
| tuple(T&& val, Ts&&... rest) | |
| : tuple<Ts...>(std::forward<Ts>(rest)...) | |
| , value_(std::forward<T>(val)) | |
| { } | |
| T value_; | |
| }; | |
| namespace detail | |
| { | |
| // Apply type properties (const, volatile, reference) of Src to Dst | |
| template <class Src, class Dst> | |
| using transcribe_const_t = std::conditional_t< | |
| std::is_const_v<std::remove_reference_t<Src>>, std::add_const_t<Dst>, Dst>; | |
| template <class Src, class Dst> | |
| using transcribe_volatile_t = std::conditional_t< | |
| std::is_volatile_v<std::remove_reference_t<Src>>, std::add_volatile_t<Dst>, Dst>; | |
| template <class Src, class Dst> | |
| using transcribe_cv_t = transcribe_const_t<Src, transcribe_volatile_t<Src, Dst>>; | |
| template <class Src, class Dst> | |
| using transcribe_lref_t = std::conditional_t< | |
| std::is_lvalue_reference_v<Src>, Dst&, Dst>; | |
| template <class Src, class Dst> | |
| using transcribe_rref_t = std::conditional_t< | |
| std::is_rvalue_reference_v<Src>, Dst&&, Dst>; | |
| template <class Src, class Dst> | |
| using transcribe_ref_t = transcribe_lref_t<Src, transcribe_rref_t<Src, Dst>>; | |
| template <class Src, class Dst> | |
| using transcribe_t = transcribe_ref_t<Src, transcribe_cv_t<Src, Dst>>; | |
| // Just some testing | |
| static_assert(std::is_same_v<transcribe_cv_t<const int&, double>, const double>); | |
| static_assert(std::is_same_v<transcribe_ref_t<const int&, double>, double&>); | |
| static_assert(std::is_same_v<transcribe_ref_t<const int&&, double>, double&&>); | |
| static_assert(std::is_same_v<transcribe_t<const int&&, double>, const double&&>); | |
| // Search tuple by type and return tuple base | |
| template <class T, class Tuple> | |
| struct tuple_element_base { | |
| using type = tuple<>; | |
| }; | |
| template <class T, class Tuple> | |
| using tuple_element_base_t = typename tuple_element_base<T, Tuple>::type; | |
| template <class T, class First, class... Rest> | |
| struct tuple_element_base<T, tuple<First, Rest...>> | |
| : std::conditional< | |
| std::is_same_v<T, First>, | |
| tuple<First, Rest...>, | |
| tuple_element_base_t<T, tuple<Rest...>> > | |
| { }; | |
| } | |
| // Find tuple element by index. Additional type | |
| // included for tuple base. | |
| template <size_t I, class Tuple> | |
| struct tuple_element; | |
| template <class First, class... Rest> | |
| struct tuple_element<0, tuple<First, Rest...>> { | |
| using type = First; | |
| using tuple_type = tuple<First, Rest...>; | |
| }; | |
| template <size_t I, class First, class... Rest> | |
| struct tuple_element<I, tuple<First, Rest...>> | |
| : tuple_element<I - 1, tuple<Rest...>> | |
| { }; | |
| template <size_t I, class Tuple> | |
| using tuple_element_t = typename tuple_element<I, Tuple>::type; | |
| // Get tuple value by index | |
| template <size_t N, class Tuple> | |
| inline constexpr decltype(auto) get(Tuple&& t) noexcept | |
| { | |
| using Base = typename tuple_element<N, std::decay_t<Tuple>>::tuple_type; | |
| return std::forward<detail::transcribe_t<Tuple, Base>>(t).value_; | |
| } | |
| // Get tuple value by type | |
| template <class T, class Tuple> | |
| inline constexpr decltype(auto) get(Tuple&& t) noexcept | |
| { | |
| using Base = detail::tuple_element_base_t<T, std::decay_t<Tuple>>; | |
| return std::forward<detail::transcribe_t<Tuple, Base>>(t).value_; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include "basic_tuple_impl.hpp" | |
| // Printer | |
| template <class... Ts> | |
| void print(const tuple<Ts...>& t) | |
| { | |
| ((std::cout << get<Ts>(t) << ", "), ...) << '\n'; | |
| } | |
| int main() | |
| { | |
| const tuple<int, std::string> tup(42, "test"); | |
| print(tup); | |
| std::cout << "by index:\n"; | |
| std::cout << " first: " << get<0>(tup) << '\n'; | |
| std::cout << " second: " << get<1>(tup) << '\n'; | |
| std::cout << "by type:\n"; | |
| std::cout << " first: " << get<int>(tup) << '\n'; | |
| std::cout << " second: " << get<std::string>(tup) << '\n'; | |
| } |
talybin
commented
Oct 21, 2019
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment