Typelists
-
-
-
- [1. Anatomy of a Typelist](#1. Anatomy of a Typelist)
- [2. Accessing Elements](#2. Accessing Elements)
- [3. Appending Types](#3. Appending Types)
- [4. Reversing a Typelist](#4. Reversing a Typelist)
- [5. Length of Typelist](#5. Length of Typelist)
- [6. Compile-Time Testing with `main`](#6. Compile-Time Testing with
main
)
- [Multiple-Choice Questions](#Multiple-Choice Questions)
- [Detailed Design Questions](#Detailed Design Questions)
- [Answers & Explanations](#Answers & Explanations)
-
- [Multiple-Choice Answers](#Multiple-Choice Answers)
- [Design Answers](#Design Answers)
- [Key Takeaways](#Key Takeaways)
-
-
1. Anatomy of a Typelist
A typelist is a compile-time structure holding a sequence of types. It is implemented via recursive template specialization.
Code: Basic Typelist Definition
cpp
template<typename... Elements>
struct Typelist {};
Test Case
cpp
using MyList = Typelist<int, double, char>;
// No runtime output; validity is checked at compile time.
2. Accessing Elements
a. Front : Get the first type.
Code
cpp
template<typename List>
struct Front;
template<typename Head, typename... Tail>
struct Front<Typelist<Head, Tail...>> {
using type = Head;
};
Test Case
cpp
using MyList = Typelist<int, double, char>;
static_assert(std::is_same_v<Front<MyList>::type, int>, "Front failed");
b. PopFront: Remove the first type.
Code
cpp
template<typename List>
struct PopFront;
template<typename Head, typename... Tail>
struct PopFront<Typelist<Head, Tail...>> {
using type = Typelist<Tail...>;
};
Test Case
cpp
using MyList = Typelist<int, double, char>;
using AfterPop = PopFront<MyList>::type;
static_assert(std::is_same_v<AfterPop, Typelist<double, char>>, "PopFront failed");
3. Appending Types
Append a type to the typelist.
Code
cpp
template<typename List, typename NewElement>
struct Append;
template<typename... Elements, typename NewElement>
struct Append<Typelist<Elements...>, NewElement> {
using type = Typelist<Elements..., NewElement>;
};
Test Case
cpp
using Original = Typelist<int, double>;
using Appended = Append<Original, char>::type;
static_assert(std::is_same_v<Appended, Typelist<int, double, char>>, "Append failed");
4. Reversing a Typelist
Reverse the order of types using recursion.
Code
cpp
template<typename List>
struct Reverse;
template<typename Head, typename... Tail>
struct Reverse<Typelist<Head, Tail...>> {
using type = typename Append<
typename Reverse<Typelist<Tail...>>::type,
Typelist<Head>
>::type;
};
template<>
struct Reverse<Typelist<>> {
using type = Typelist<>;
};
Test Case
cpp
using MyList = Typelist<int, double, char>;
using Reversed = Reverse<MyList>::type;
static_assert(std::is_same_v<Reversed, Typelist<char, double, int>>, "Reverse failed");
5. Length of Typelist
Calculate the number of types.
Code
cpp
template<typename List>
struct Length;
template<typename... Elements>
struct Length<Typelist<Elements...>> {
static constexpr std::size_t value = sizeof...(Elements);
};
Test Case
cpp
using MyList = Typelist<int, double, char>;
static_assert(Length<MyList>::value == 3, "Length failed");
6. Compile-Time Testing with main
Use static_assert
to validate typelist operations at compile time.
Code
cpp
#include <type_traits>
#include <iostream>
int main() {
// Tests are compile-time; no runtime output.
std::cout << "All tests passed at compile time!\n";
return 0;
}
Multiple-Choice Questions
-
Which of the following correctly describe the structure of a Typelist?
- A) A runtime-linked list of type pointers
- B) A recursive template structure with a head and tail
- C) A class template with variadic parameters
- D) A tuple-like structure with fixed-size type storage
-
What is the time complexity of accessing the Nth element in a Typelist using linear recursion?
- A) O(1)
- B) O(N)
- C) O(log N)
- D) O(N^2)
-
Which techniques are valid for reversing a Typelist?
- A) Using recursive template specialization
- B) Using
constexpr
functions at runtime - C) Leveraging pack expansion with index sequences
- D) Storing types in a temporary tuple
-
What is required to implement a "best match" algorithm for Typelists?
- A) Partial template specialization
- B) SFINAE (Substitution Failure Is Not An Error)
- C) Runtime type comparison
- D) Template template parameters
-
Which are valid applications of Typelists?
- A) Implementing compile-time state machines
- B) Generating dispatch tables for variant types
- C) Runtime polymorphism
- D) Serializing objects to JSON
-
How does inserting a type into a Typelist work?
- A) Requires O(N) template instantiations
- B) Uses
std::conditional
for branch selection - C) Relies on
if constexpr
for recursion - D) Mutates the original Typelist
-
What is the purpose of
IndexList
/IndexSequence
in Typelist algorithms?- A) To enable pack expansion optimizations
- B) To store runtime indices for type access
- C) To generate compile-time integer sequences
- D) To validate type boundaries
-
Which operations are possible with nontype Typelists?
- A) Sorting integers at compile time
- B) Storing floating-point values
- C) Deduction of nontype template parameters
- D) Runtime type introspection
-
What is a key advantage of using pack expansions over recursive template instantiations?
- A) Reduced compile-time memory usage
- B) Support for runtime polymorphism
- C) Elimination of template recursion depth limits
- D) Simpler syntax
-
Which C++ features are essential for Typelist implementations?
- A) Variadic templates
- B)
constexpr
functions - C) RTTI (Runtime Type Information)
- D) Template partial specialization
Detailed Design Questions
-
Implement a
Reverse
algorithm for Typelists using both recursive and pack-expansion approaches. Compare their compile-time performance.cpp// Recursive approach template<typename TList> struct Reverse; template<> struct Reverse<NullType> { using type = NullType; }; template<typename Head, typename Tail> struct Reverse<Typelist<Head, Tail>> { using type = Append<typename Reverse<Tail>::type, Head>; }; // Pack-expansion approach template<typename... Ts> struct Reverse<std::tuple<Ts...>> { using type = std::tuple<typename Reverse<std::tuple<Ts...>>::type...>; };
-
Design a
InsertionSort
algorithm for a Typelist of integers, sorting them at compile time.cpptemplate<typename TList> struct InsertionSort; template<> struct InsertionSort<NullType> { using type = NullType; }; template<typename Head, typename Tail> struct InsertionSort<Typelist<Head, Tail>> { using sortedTail = typename InsertionSort<Tail>::type; using type = InsertSorted<sortedTail, Head>; }; template<typename T, typename U, typename... Ts> struct InsertSorted<Typelist<U, Ts...>, T> { using type = std::conditional_t<(T < U), Typelist<T, U, Ts...>, Typelist<U, typename InsertSorted<Typelist<Ts...>, T>::type>>; };
-
Create a
Transform
algorithm that converts a Typelist of types into a Typelist of their sizes (e.g.,sizeof(int)
→size_t
).cpptemplate<template<typename> class F, typename TList> struct Transform; template<template<typename> class F> struct Transform<F, NullType> { using type = NullType; }; template<template<typename> class F, typename Head, typename Tail> struct Transform<F, Typelist<Head, Tail>> { using type = Typelist<F<Head>, typename Transform<F, Tail>::type>; };
-
Implement a
Filter
algorithm that removes all types from a Typelist wherestd::is_integral_v<T>
is false.cpptemplate<template<typename> class Pred, typename TList> struct Filter; template<template<typename> class Pred> struct Filter<Pred, NullType> { using type = NullType; }; template<template<typename> class Pred, typename Head, typename Tail> struct Filter<Pred, Typelist<Head, Tail>> { using type = std::conditional_t<Pred<Head>::value, Typelist<Head, typename Filter<Pred, Tail>::type>, typename Filter<Pred, Tail>::type>; };
-
Design a
Cons
-style Typelist supporting O(1) head/tail access and benchmark it against the standard recursive approach.cpptemplate<typename... Ts> struct ConsTypelist; template<typename Head, typename... Tail> struct ConsTypelist<Head, Tail...> { using head = Head; using tail = ConsTypelist<Tail...>; }; template<> struct ConsTypelist<> { /* Base case */ };
Answers & Explanations
Multiple-Choice Answers
-
B, C
Typelists are recursive template structures (B) and use variadic parameters ©.
A/D: Runtime structures and fixed-size storage are incorrect.
-
B
Linear recursion results in O(N) complexity for Nth element access.
-
A, C
Recursive specialization (A) and pack expansions with index sequences © are valid.
B:
constexpr
works at compile time but isn't used here. D: Tuples aren't part of Typelist reversal. -
A, B
Partial specialization (A) and SFINAE (B) are needed for compile-time type matching.
-
A, B
Typelists enable compile-time state machines (A) and variant dispatch tables (B).
C/D: Runtime features are unrelated.
-
A, B
Insertion requires O(N) instantiations (A) and
std::conditional
(B).C:
if constexpr
isn't used here. D: Typelists are immutable. -
A, C
IndexLists enable pack expansion optimizations (A) and compile-time sequences ©.
B/D: Runtime indices and validation are irrelevant.
-
A, C
Nontype Typelists sort integers (A) and deduce parameters ©.
B: Floating points are invalid. D: No runtime introspection.
-
A, C
Pack expansions reduce memory (A) and avoid recursion limits ©.
B/D: Irrelevant to compile-time optimizations.
-
A, D
Variadic templates (A) and partial specialization (D) are essential.
B:
constexpr
isn't required. C: RTTI is runtime-only.
Design Answers
-
Reverse Implementation
cpp// Test case using MyList = Typelist<int, char, double>; using Reversed = Reverse<MyList>::type; // Typelist<double, char, int> static_assert(std::is_same_v<Get<0, Reversed>, double>);
-
InsertionSort
cppusing IntList = Typelist<3, 1, 4, 2>; using Sorted = InsertionSort<IntList>::type; // Typelist<1, 2, 3, 4> static_assert(Get<0, Sorted>::value == 1);
-
Transform
cpptemplate<typename T> struct SizeOf { static constexpr size_t value = sizeof(T); }; using Sizes = Transform<SizeOf, Typelist<int, double>>::type; // Typelist<4, 8>
-
Filter
cppusing Filtered = Filter<std::is_integral, Typelist<int, char, double>>::type; // Typelist<int, char>
-
ConsTypelist Benchmark
cppusing ConsList = ConsTypelist<int, char, double>; static_assert(std::is_same_v<typename ConsList::head, int>);
Key Takeaways
- Typelists enable compile-time type manipulation.
- Recursive templates are central to operations like
Reverse
. static_assert
validates typelist logic during compilation.- Each operation (e.g.,
Front
,Append
) is a template metafunction returning a type or value.
This approach leverages C++'s type system to enforce correctness without runtime overhead.