Created
October 28, 2017 18:10
-
-
Save pudov/d32432d2742f9a7c68f4b0186132ee24 to your computer and use it in GitHub Desktop.
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 <type_traits> | |
| template<typename T, typename U> | |
| constexpr bool same() | |
| { | |
| return std::is_same<T,U>::value; | |
| } | |
| template<typename TL, size_t i> | |
| struct type_list_index_helper | |
| { | |
| static_assert(i <= TL::size(), ""); | |
| static_assert(i != 0, ""); | |
| using type = typename type_list_index_helper<typename TL::tail, i - 1>::type; | |
| }; | |
| template<typename TL> | |
| struct type_list_index_helper<TL, 0> | |
| { | |
| using type = typename TL::head; | |
| }; | |
| template<typename T, typename ... Ts> | |
| struct type_list_tail_helper | |
| { | |
| static_assert(sizeof...(Ts) != 0, ""); | |
| using type = typename type_list_tail_helper<Ts...>::type; | |
| }; | |
| template<typename T> | |
| struct type_list_tail_helper<T> | |
| { | |
| using type = T; | |
| }; | |
| template<typename ...> | |
| struct type_list; | |
| template<typename T, typename ... Ts> | |
| struct type_list<T, Ts...> | |
| { | |
| using head = T; | |
| using list = type_list<T, Ts...>; | |
| using tail = type_list<Ts...>; | |
| using last = typename type_list_tail_helper<T, Ts...>::type; | |
| template<typename X> | |
| static constexpr bool contains() | |
| { | |
| return same<X, T>() || tail::template contains<X>(); | |
| } | |
| static constexpr size_t size() | |
| { | |
| return 1 + sizeof...(Ts); | |
| } | |
| template<typename X> | |
| static constexpr int ind() | |
| { | |
| return !same<X, T>() | |
| ? (tail::template ind<X>() >= 0 ? 1 + tail::template ind<X>() : -1) | |
| : 0; | |
| } | |
| template<size_t i> | |
| using at = typename type_list_index_helper<list, i>::type; | |
| template<typename ... Xs> | |
| using append = type_list<head, Ts..., Xs...>; | |
| template<typename ... Xs> | |
| using prepend = type_list<Xs..., head, Ts...>; | |
| }; | |
| template<> | |
| struct type_list<> | |
| { | |
| static constexpr size_t size() | |
| { | |
| return 0; | |
| } | |
| template<typename X> | |
| static constexpr bool contains() | |
| { | |
| return false; | |
| } | |
| template<typename X> | |
| static constexpr int ind() | |
| { | |
| return -1; | |
| } | |
| template<typename ... Xs> | |
| using append = type_list<Xs...>; | |
| template<typename ... Xs> | |
| using prepend = append<Xs...>; | |
| }; | |
| template<typename TL, typename UL> | |
| struct type_list_concat_helper | |
| { | |
| using type = typename type_list_concat_helper< | |
| typename TL::template append<typename UL::head>, | |
| typename UL::tail>::type; | |
| }; | |
| template<typename TL> | |
| struct type_list_concat_helper<TL, type_list<>> | |
| { | |
| using type = TL; | |
| }; | |
| template<typename UL> | |
| struct type_list_concat_helper<type_list<>, UL> | |
| { | |
| using type = UL; | |
| }; | |
| template <typename TL, typename ... VLs> | |
| struct type_list_concat; | |
| template <typename TL> | |
| struct type_list_concat<TL> | |
| { | |
| using type = TL; | |
| }; | |
| template <typename TL, typename UL, typename ... VLs> | |
| struct type_list_concat<TL, UL, VLs...> | |
| { | |
| using type = typename type_list_concat< | |
| typename type_list_concat_helper<TL, UL>::type, | |
| VLs...>::type; | |
| }; | |
| template<typename TL> | |
| struct type_list_remove_last | |
| { | |
| static_assert(TL::size() != 0, ""); | |
| using type = typename std::conditional< | |
| TL::size() == 1, | |
| type_list<>, | |
| typename type_list_concat< | |
| type_list<typename TL::head>, | |
| typename type_list_remove_last<typename TL::tail>::type | |
| >::type | |
| >::type; | |
| }; | |
| template<> | |
| struct type_list_remove_last<type_list<>> | |
| { | |
| using type = type_list<>; | |
| }; | |
| template<typename TL, size_t i, size_t j> | |
| struct type_list_slice | |
| { | |
| static_assert(i <= j, ""); | |
| static_assert(i <= TL::size(), ""); | |
| static_assert(j <= TL::size(), ""); | |
| using type = typename std::conditional< | |
| i == j, | |
| type_list<>, | |
| typename type_list_concat< | |
| type_list<typename TL::template at<i>>, | |
| typename type_list_slice<TL, i + 1, j>::type | |
| >::type | |
| >::type; | |
| }; | |
| template<typename TL, size_t i> | |
| struct type_list_slice<TL, i, i> | |
| { | |
| using type = type_list<>; | |
| }; | |
| using list = type_list<int, char, std::string, char*>; | |
| static_assert(list::contains<char>(), ""); | |
| static_assert(list::size() == 4, ""); | |
| static_assert(same<int, list::at<0>>(), ""); | |
| static_assert(same<char, list::at<1>>(), ""); | |
| static_assert(same<std::string, list::at<2>>(), ""); | |
| static_assert(same<char*, list::at<3>>(), ""); | |
| // static_assert(same<char*, list::at<4>>(), ""); | |
| static_assert(list::ind<int*>() == -1, ""); | |
| static_assert(list::ind<int>() == 0, ""); | |
| static_assert(list::ind<char>() == 1, ""); | |
| static_assert(list::ind<std::string>() == 2, ""); | |
| static_assert(list::ind<char*>() == 3, ""); | |
| using modified = list::prepend<long, short>::append<bool>; | |
| static_assert(modified::contains<char>(), ""); | |
| static_assert(modified::size() == 7, ""); | |
| static_assert(same<type_list<long, short, int, char, std::string, char*, bool>, modified>(), ""); | |
| // using head_only_list = type_list<char*>; | |
| using head_only_list = type_list<>::prepend<char*>; | |
| static_assert(head_only_list::size() == 1, ""); | |
| static_assert(head_only_list::ind<char*>() == 0, ""); | |
| static_assert(head_only_list::ind<char>() == -1, ""); | |
| static_assert(same<char*, head_only_list::at<0>>(), ""); | |
| using empty_list = type_list<>; | |
| static_assert(empty_list::size() == 0, ""); | |
| static_assert(empty_list::ind<int>() == -1, ""); | |
| using mega_list = typename type_list_concat<list, empty_list, head_only_list, modified>::type; | |
| static_assert(mega_list::size() == 12, ""); | |
| static_assert(same<type_list<int, char, std::string, char*, char*, long, short, int, char, std::string, char*, bool>, mega_list>(), ""); | |
| using concat_list = typename type_list_concat<list, head_only_list>::type; | |
| using shrinked_list = type_list_remove_last<list>::type; | |
| static_assert(same<type_list<int, char, std::string>, shrinked_list>(), ""); | |
| static_assert(same<typename type_list_remove_last<head_only_list>::type, empty_list>(), ""); | |
| static_assert(same<typename type_list_remove_last<empty_list>::type, empty_list>(), ""); | |
| using slice = typename type_list_slice<head_only_list, 0, 1>::type; | |
| static_assert(same<head_only_list, slice>(), ""); | |
| using empty_slice = typename type_list_slice<head_only_list, 0, 0>::type; | |
| static_assert(same<empty_list, empty_slice>(), ""); | |
| using mega_slice = typename type_list_slice<mega_list, 4, 8>::type; | |
| static_assert(mega_slice::size() == 4, ""); | |
| static_assert(same<type_list<char*, long, short, int>, mega_slice>(), ""); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment