AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

12 Templates and generic programming / Checkpoint

Checkpoint — Templates and generic programming

28 min · +25 XP · 3 exercises · 13 questions

Exercises0/3
Quiz · 70% to clear13 q

This checkpoint covers the whole module: function templates and deduction, class templates with out-of-class members and CTAD, full and partial specialisation and the traits pattern, non-type parameters and packs with fold expressions, concepts and constrained auto, and the type traits behind if constexpr dispatch.

How it works. Thirteen questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • Why does max_of(3, 2.5) fail to compile, and what are the two ways to fix it?
  • Why must a template's definition live in the header rather than a .cpp file?
  • What does std::vector v{3} deduce, and how many elements does it hold?
  • Why is a function template overloaded rather than specialised?
  • Which fold forms are legal on an empty pack?
  • Is bool a std::integral, and why does that matter for an overload set?
  • Why is std::is_same_v<T, std::string> false inside f(T&& x) for a std::string lvalue?

The three programs are a Queue<T> instantiated for the element type named on the first line, a statistics report whose overloads are chosen by concepts, and a Table<K, V> whose header line comes from a TypeName trait. Read the type word first; everything else follows from it.

Common questions

Why is a function template overloaded rather than specialised?

Because a full specialisation of a function template is not an overload candidate: the compiler picks the best primary template or non-template first, and a better-matching template can hide the specialisation. Function templates also cannot be partially specialised. A plain overload takes part in resolution and wins exact-match ties.

Which fold forms are legal on an empty pack?

Every binary fold, such as (0 + ... + xs), because it supplies its own initial value. Among unary folds, only those over &&, || and the comma operator, which give true, false and nothing. (xs + ...) on an empty pack does not compile.

Is bool a std::integral, and why does that matter?

Yes — bool is an integer type to the language, so it satisfies std::integral. In an overload set constrained on std::integral, a bool argument therefore picks the integer overload; add && !std::same_as<T, bool> when bool must go elsewhere.

C++ Templates Quiz: Deduction, Concepts and Traits Practice

Practise C++ generic programming with 13 questions and three programs on templates, CTAD, specialisation, fold expressions, concepts and traits.

  • Course: C++ study plan
  • Module: Templates and generic programming
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 28 min
  • Runtime: Clang 18 · C++20

Checkpoint — Templates and generic programming is the checkpoint that closes the Templates and generic programming module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the whole module: function templates and deduction, class templates with out-of-class members and CTAD, full and partial specialisation and the traits pattern, non-type parameters and packs with fold expressions, concepts and constrained auto, and the type traits behind if constexpr dispatch.

How it works. Thirteen questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • Why does max_of(3, 2.5) fail to compile, and what are the two ways to fix it?
  • Why must a template's definition live in the header rather than a .cpp file?
  • What does std::vector v{3} deduce, and how many elements does it hold?
  • Why is a function template overloaded rather than specialised?
  • Which fold forms are legal on an empty pack?
  • Is bool a std::integral, and why does that matter for an overload set?
  • Why is std::is_same_v<T, std::string> false inside f(T&& x) for a std::string lvalue?

The three programs are a Queue<T> instantiated for the element type named on the first line, a statistics report whose overloads are chosen by concepts, and a Table<K, V> whose header line comes from a TypeName trait. Read the type word first; everything else follows from it.

Common questions

Why is a function template overloaded rather than specialised?

Because a full specialisation of a function template is not an overload candidate: the compiler picks the best primary template or non-template first, and a better-matching template can hide the specialisation. Function templates also cannot be partially specialised. A plain overload takes part in resolution and wins exact-match ties.

Which fold forms are legal on an empty pack?

Every binary fold, such as (0 + ... + xs), because it supplies its own initial value. Among unary folds, only those over &&, || and the comma operator, which give true, false and nothing. (xs + ...) on an empty pack does not compile.

Is bool a std::integral, and why does that matter?

Yes — bool is an integer type to the language, so it satisfies std::integral. In an overload set constrained on std::integral, a bool argument therefore picks the integer overload; add && !std::same_as<T, bool> when bool must go elsewhere.

Exercises

Queue<T> for the element type on the first line

Write a class template Queue<T> — first in, first out — over a std::vector<T> and a head index, with push, pop, front, size and print; define pop, front and print outside the class body with their own template headers. A function template run<T>() processes the commands; main reads the type word and calls run<int>() or run<std::string>().

Commands, one per line: push <v>; pop (print popped <v> or empty); front (print front=<v> or empty); size (print size=<k>); print (print queue: <front> … <back> or queue: (empty)).

Input: the type word (int or string), then commands. Output: one line per pop, front, size and print.

int
push 1
push 2
push 3
print
pop
front
size

prints

queue: 1 2 3
popped 1
front=2
size=2

A statistics report chosen by concepts

Write a concept Number = std::integral<T> || std::floating_point<T>, a helper template <Number T> T spread(const std::vector<T>&) returning max - min, and three overloads of stats(const std::vector<T>& v):

  • template <std::integral T>: integral n=<k> sum=<sum> min=<min> max=<max> spread=<spread> — the sum in a long long.
  • template <std::floating_point T>: floating n=<k> mean=<mean> min=<min> max=<max> spread=<spread> — all four with two decimals.
  • template <typename T> (unconstrained): text n=<k> longest=<word> chars=<total characters> — the first longest word on a tie.

Read n, then n lines of <type> <k> <v1> … <vk> with <type> one of int, double, string and k at least 1.

Input: n, then n lines. Output: one line per input line.

3
int 4 1 2 3 4
double 2 1.5 2.5
string 3 pear banana kiwi

prints

integral n=4 sum=10 min=1 max=4 spread=3
floating n=2 mean=2.00 min=1.50 max=2.50 spread=1.00
text n=3 longest=banana chars=14

Table<K, V> with a TypeName header

Write a trait TypeName<T> — a primary template whose value is "unknown" and full specialisations giving "int", "double" and "std::string" — plus a variable template type_name_v<T>. Then a class template Table<K, V> over a std::map<K, V> with set(key, value) (a repeated key replaces the earlier value) and print(), which writes the header Table<<K name>, <V name>> from the trait, then every row in key order as <key> -> <value> (a double value with two decimals — use if constexpr on std::is_floating_point_v<V>), then rows=<count>.

The first line names K (int or string) and V (int, double or string), so there are six possible instantiations; dispatch through a run<K, V>() function template. Then n, then n lines of <key> <value>. Note that integer keys order numerically while string keys order lexicographically — the same input prints differently under Table<int, …> and Table<std::string, …>.

Input: the two type words, n, then n rows. Output: the header, the rows in key order, then rows=<count>.

int string
3
10 ten
2 two
7 seven

prints

Table<int, std::string>
2 -> two
7 -> seven
10 -> ten
rows=3

In this module: Templates and generic programming

← Type traits and metaprogramming — computing with types · The container zoo — choosing a container →