A typelist is a compile-time structure holding a sequence of types. It is implemented via recursive template specialization.
Code: Basic Typelist Definition
template<typename... Elements>
struct Typelist {};
Test Case
using MyList = Typelist<int, double, char>;
// No runtime output; validity is checked at compile time.
a. Front: Get the first type.
Code
template<typename List>
struct Front;
template<typename Head, typename... Tail>
struct Front<Typelist<Head, Tail...>> {
using type = Head;
};
Test Case
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
template<typename List>
struct PopFront;
template<typename Head, typename... Tail>
struct PopFront<Typelist<Head, Tail...>> {
using type = Typelist<Tail...>;
};
Test Case
using MyList = Typelist<int, double, char>;
using AfterPop = PopFront<MyList>::type;
static_assert(std::is_same_v<AfterPop, Typelist<double, char>>, "PopFront failed");
Append a type to the typelist.
Code
template<typename List, typename NewElement>
struct Append;
template<typename... Elements, typename NewElement>
struct Append<Typelist<Elements...>, NewElement> {
using type = Typelist<Elements..., NewElement>;
};
Test Case
using Original = Typelist<int, double>;
using Appended = Append<Original, char>::type;
static_assert(std::is_same_v<Appended, Typelist<int, double, char>>, "Append failed");
Reverse the order of types using recursion.
Code
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
using MyList = Typelist<int, double, char>;
using Reversed = Reverse<MyList>::type;
static_assert(std::is_same_v<Reversed, Typelist<char, double, int>>, "Reverse failed");
Calculate the number of types.
Code
template<typename List>
struct Length;
template<typename... Elements>
struct Length<Typelist<Elements...>> {
static constexpr std::size_t value = sizeof...(Elements);
};
Test Case
using MyList = Typelist<int, double, char>;
static_assert(Length<MyList>::value == 3, "Length failed");
main
Use static_assert
to validate typelist operations at compile time.
Code
#include
#include
int main() {
// Tests are compile-time; no runtime output.
std::cout << "All tests passed at compile time!\n";
return 0;
}
Which of the following correctly describe the structure of a Typelist?
What is the time complexity of accessing the Nth element in a Typelist using linear recursion?
Which techniques are valid for reversing a Typelist?
constexpr
functions at runtimeWhat is required to implement a “best match” algorithm for Typelists?
Which are valid applications of Typelists?
How does inserting a type into a Typelist work?
std::conditional
for branch selectionif constexpr
for recursionWhat is the purpose of IndexList
/IndexSequence
in Typelist algorithms?
Which operations are possible with nontype Typelists?
What is a key advantage of using pack expansions over recursive template instantiations?
Which C++ features are essential for Typelist implementations?
constexpr
functionsImplement a Reverse
algorithm for Typelists using both recursive and pack-expansion approaches. Compare their compile-time performance.
// 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.
template<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
).
template<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 where std::is_integral_v
is false.
template<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.
template<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 */ };
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.
Reverse Implementation
// Test case
using MyList = Typelist<int, char, double>;
using Reversed = Reverse<MyList>::type; // Typelist
static_assert(std::is_same_v<Get<0, Reversed>, double>);
InsertionSort
using IntList = Typelist<3, 1, 4, 2>;
using Sorted = InsertionSort<IntList>::type; // Typelist<1, 2, 3, 4>
static_assert(Get<0, Sorted>::value == 1);
Transform
template<typename T> struct SizeOf { static constexpr size_t value = sizeof(T); };
using Sizes = Transform<SizeOf, Typelist<int, double>>::type; // Typelist<4, 8>
Filter
using Filtered = Filter<std::is_integral, Typelist<int, char, double>>::type; // Typelist
ConsTypelist Benchmark
using ConsList = ConsTypelist<int, char, double>;
static_assert(std::is_same_v<typename ConsList::head, int>);
Reverse
.static_assert
validates typelist logic during compilation.Front
, Append
) is a template metafunction returning a type or value.This approach leverages C++'s type system to enforce correctness without runtime overhead.