#if 0 set -xe g++ -std=c++11 -fsyntax-only type_list.cc clang++ -std=c++11 -fsyntax-only type_list.cc exit 0 #endif #include // Simple type list. // // A type list, as the name suggests, is a type which holds a list of types. // Type lists can be arbitrarily nested and contain other type lists. // // Given a type list one can apply different algorithms, like adding types, // flattening type lists and so on, where some are implement here. // // This is merely for fun and serves as a brain jogging exercise. namespace tl { template struct type_list; // -- GET ---------------------------------------------------------------------- template struct get { static_assert(Index < sizeof...(Tail) + 1, "index out of bounds"); using type = typename get::type; }; template struct get<0, Head, Tail...> { using type = Head; }; template using get_t = typename get::type; // -- PREPEND ------------------------------------------------------------------ template struct prepend; template using prepend_t = typename prepend::type; template struct prepend> { using type = type_list; }; // -- FLATTEN ------------------------------------------------------------------ template struct flatten; template using flatten_t = typename flatten::type; template struct flatten { using type = prepend_t>; }; // Specialization (1): // Unpack inner types of LEADING type_list parameter and recursively flatten. template struct flatten, Tail...> { using type = flatten_t; }; // Specialization (2): // Unpack inner types of SINGLE type_list parameter and recursively flatten. template struct flatten> { using type = flatten_t; }; // Specialization (3): // Pack single non-type_list type into a type_list (recursive base case). template struct flatten { using type = type_list; }; // -- TYPE_LIST ---------------------------------------------------------------- template struct type_list { using self = type_list; static constexpr std::size_t len = sizeof...(Tail) + 1 /* Head */; // Get type at specific INDEX. template using get = get_t; // Prepend TYPE to the type list. template using prepend = prepend_t; // Flatten nested type lists. using flatten = flatten_t; }; } // namespace tl // -- TESTS -------------------------------------------------------------------- #if __cplusplus >= 201703L #define STATIC_ASSERT(...) static_assert(__VA_ARGS__); #else #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, "test failed"); #endif // Flat type list. namespace test1 { using list = tl::type_list; STATIC_ASSERT(list::len == 3); STATIC_ASSERT(std::is_same, int>::value); STATIC_ASSERT(std::is_same, char>::value); STATIC_ASSERT(std::is_same, int>::value); STATIC_ASSERT(std::is_same, tl::type_list>::value); STATIC_ASSERT(std::is_same::value); } // namespace test1 // Nested type lists. namespace test2 { using list = tl::type_list, void>; STATIC_ASSERT(list::len == 3); STATIC_ASSERT(std::is_same, int>::value); STATIC_ASSERT(std::is_same, tl::type_list>::value); STATIC_ASSERT(std::is_same, void>::value); STATIC_ASSERT( std::is_same< list::prepend>, tl::type_list, int, tl::type_list, void>>:: value); using flat = list::flatten; STATIC_ASSERT(flat::len == 3); STATIC_ASSERT(std::is_same, int>::value); STATIC_ASSERT(std::is_same, char>::value); STATIC_ASSERT(std::is_same, void>::value); } // namespace test2 // Deeply nested type lists. namespace test3 { using list = tl::type_list, int>>; STATIC_ASSERT(list::len == 1); STATIC_ASSERT( std::is_same, tl::type_list, int>>::value); using flat = list::flatten; STATIC_ASSERT(flat::len == 3); STATIC_ASSERT(std::is_same, char>::value); STATIC_ASSERT(std::is_same, void>::value); STATIC_ASSERT(std::is_same, int>::value); } // namespace test3 #undef STATIC_ASSERT