Templates
Template instantiation, specialization, SFINAE, CRTP, variadic templates, and metaprogramming.
35 questions
JuniorTheoryVery commonWhat are class templates and function templates?
What are class templates and function templates?
A template is a blueprint parameterised over types or values: a function template generates a family of functions, a class template a family of classes. The compiler instantiates a concrete version on use, explicitly or via argument deduction.
Common mistakes
- ✗Putting template implementations in a .cpp file — the compiler needs the full definition at the point of instantiation, so templates must be defined in headers
- ✗Confusing template parameters with runtime parameters
- ✗Assuming the same template instantiation is shared across translation units — each TU gets its own copy (the linker merges them via weak symbols)
Follow-up questions
- →What is the difference between a type parameter and a non-type template parameter?
- →When would you prefer a function template over a regular overloaded function?
JuniorTheoryVery commonWhat is template instantiation? Implicit vs explicit?
What is template instantiation? Implicit vs explicit?
Template instantiation is the compiler generating a concrete class or function from a template by substituting arguments. Implicit happens automatically on first use; explicit forces it in a chosen TU and (with extern template) can suppress it elsewhere.
Common mistakes
- ✗Not knowing that only the members actually used are implicitly instantiated — unused methods of a class template are not compiled
- ✗Placing explicit instantiation definitions in headers — this should be in exactly one .cpp file
- ✗Forgetting
extern templateto suppress implicit instantiation in every TU when using explicit instantiation to reduce compile times
Follow-up questions
- →How does
extern templatereduce compile times? - →What is the difference between a template definition and a template declaration?
MiddleTheoryVery commonWhat are the template type deduction rules?
What are the template type deduction rules?
Template type deduction has three cases: by-value (top-level qualifiers stripped), by-reference (qualifiers preserved), and universal reference T&& (deduces lvalue ref via reference collapsing). Arrays and functions decay to pointers in by-value deduction.
Common mistakes
- ✗Expecting
constto be deduced when passing by value — by-value deduction always strips top-level cv-qualifiers - ✗Confusing
T&&(universal reference / forwarding reference) with an rvalue reference — depends on context - ✗Overlooking array-to-pointer decay:
template<typename T> void f(T x)withf(arr)deducesT = int*, notint[N]
Follow-up questions
- →How does
autotype deduction mirror template deduction? Where do they differ (brace-init)? - →What is reference collapsing and when does it occur?
JuniorTheoryCommonWhy must template class implementations go in headers?
Why must template class implementations go in headers?
The compiler needs the full template definition at every instantiation point. An implementation in a .cpp is invisible to other TUs and causes linker errors. Fix: keep it in the header. Alternative: explicit instantiation plus extern template.
Common mistakes
- ✗Putting the implementation in a .cpp and getting 'undefined reference' linker errors
- ✗Forgetting that an explicit instantiation in one .cpp +
extern templatein headers is a valid but often-overlooked alternative - ✗Not realising this is a compile-time constraint, not a language design flaw
Follow-up questions
- →How does the
exportkeyword (removed in C++11) attempt to address this? - →How do C++20 modules change the situation?
JuniorTheoryCommonWhat is template specialization? Full vs partial?
What is template specialization? Full vs partial?
Template specialization provides an alternative implementation for specific arguments. Full specialization fixes all parameters and is written template<>; partial specialization fixes some or adds constraints and is allowed only for class templates — not functions.
Common mistakes
- ✗Trying to partially specialise a function template — use overloading or
if constexprinstead - ✗Defining a full specialisation in a header without
inline— leads to multiple-definition errors - ✗Ordering specialisations incorrectly — the primary template must be declared before any specialisation
Follow-up questions
- →When is explicit specialisation preferred over
if constexprinside the template? - →How does the compiler choose between a primary template and its specialisations?
MiddleTheoryCommonWhat are fold expressions and what forms do they take?
What are fold expressions and what forms do they take?
Fold expressions (C++17) collapse a parameter pack with a binary operator in four forms: unary right (args op ...), left (... op args), binary right (args op ... op init), left (init op ... op args). Empty-pack identity is defined only for &&, ||, ,.
Common mistakes
- ✗Folding with
+over an empty pack — compile error, no identity - ✗Confusing left and right fold direction with associativity of the operator
- ✗Wrapping non-pack expression in fold — only packs work
Follow-up questions
- →How do you implement
print(args...)with fold and<<? - →Why does
(args, ...)work for empty pack?
MiddleTheoryCommonWhat does if constexpr do and how does it differ from a regular if?
What does if constexpr do and how does it differ from a regular if?
if constexpr (C++17) discards the not-taken branch at compile time — it need not compile for the current instantiation, letting one template handle type-dependent paths. A regular if requires both branches to compile.
Common mistakes
- ✗Using
if constexprwith a runtime condition — not allowed, must be compile-time - ✗Forgetting
elseand having unintended fall-through after dependent code - ✗Putting non-discardable code in the false branch (e.g.
static_assert) — fires regardless
Follow-up questions
- →How does
if constexprinteract withstatic_assert? - →Why is
if constexprcleaner than tag dispatch for many cases?
MiddleTheoryCommonWhat is a non-type template parameter and what kinds are allowed?
What is a non-type template parameter and what kinds are allowed?
A non-type parameter takes a value, not a type (template<size_t N> struct Array {T data[N];}). Allowed pre-C++20: integral, enum, pointer/reference with linkage, nullptr_t. C++17 added auto; C++20 added structural class types like fixed-size strings.
Common mistakes
- ✗Trying to pass a
std::stringas non-type parameter pre-C++20 — not allowed - ✗Forgetting
auto(C++17) when the type is hard to spell or template-deduced - ✗Mixing template type and non-type parameters in the wrong order
Follow-up questions
- →How do C++20 fixed strings work as template parameters?
- →What is structural equality and why is it required for class non-type params?
MiddleTheoryCommonHow does parameter pack expansion work and what patterns can you express with it?
How does parameter pack expansion work and what patterns can you express with it?
A pattern followed by ... repeats for each pack element: f(args)... calls f per arg, Ts... expands a type pack, (args + ...) folds. Transformations like f(g(args)...) are allowed; std::index_sequence lets you unpack a tuple.
Common mistakes
- ✗Forgetting to put
...at the end of the pattern — only the first element expands - ✗Confusing fold expression
(args + ...)with pack expansionargs... - ✗Trying to expand a pack outside a context that allows it (e.g. plain assignment)
Follow-up questions
- →How does
std::applyuseindex_sequenceto unpack a tuple? - →Why is
(args = 0, ...)valid butargs = 0...is not?
MiddleTheoryCommonWhat are the reference collapsing rules, and why do forwarding references depend on them?
What are the reference collapsing rules, and why do forwarding references depend on them?
When references stack, they collapse: any combination with an lvalue ref yields T&, and only T&& && yields T&&. A forwarding reference T&& deduces T as U& for lvalues, so U& && collapses to U&; for rvalues T = U, giving U&&. That's how it preserves value category.
Common mistakes
- ✗Calling
T&&an rvalue reference whenTis a deduced template parameter — it is a forwarding reference - ✗Believing
const T&&orvector<T>&&is a forwarding reference — only a plain deducedT&&qualifies - ✗Using
std::moveinstead ofstd::forwardin a forwarding context, silently moving from lvalues
Follow-up questions
- →Why is
auto&&also a forwarding reference butconst auto&&is not? - →How does
std::forward<T>use the deducedTto restore the value category?
MiddleTheoryCommonWhat is SFINAE and what is it used for?
What is SFINAE and what is it used for?
SFINAE (Substitution Failure Is Not An Error): if substituting template arguments yields an invalid type or expression in the immediate context, the compiler silently drops the overload. Powers std::enable_if for conditional overload selection.
Common mistakes
- ✗Triggering SFINAE in the function body — it only applies to the immediate context of template parameter substitution, not the body
- ✗Using SFINAE where C++20 concepts are cleaner and give better error messages
- ✗Writing deeply nested
enable_ifchains that become unreadable — preferif constexprfor branches inside a function
Follow-up questions
- →How do C++20 concepts replace most SFINAE use cases?
- →What is
std::void_tand how does it detect type members?
SeniorTheoryCommonWhat are C++20 concepts and how do they replace SFINAE?
What are C++20 concepts and how do they replace SFINAE?
A concept is a named compile-time predicate over template parameters used to constrain templates (template<Number T> T add(T,T);). Errors become readable — instead of SFINAE pages, 'T does not satisfy Number'. Concepts rank overloads by subsumption.
Common mistakes
- ✗Writing concepts that don't actually check what you mean — concept passes for unintended types
- ✗Using
requires (T t) { t + t; }and forgetting that this checks compilation, not semantics - ✗Mixing SFINAE and concepts in the same overload set — confusing precedence
Follow-up questions
- →What's the difference between requires-clause and requires-expression?
- →How does concept subsumption rank overloads?
SeniorTheoryCommonWhat's the difference between a requires-clause and a requires-expression?
What's the difference between a requires-clause and a requires-expression?
A requires-clause constrains a template (requires Number<T>); a requires-expression checks whether operations are valid (requires (T t) { t+t; }). Combined as requires requires (T t) { ... } — outer clause, inner expression.
Common mistakes
- ✗Using
requires-expressionsyntax where a clause is expected (aftertemplate<>or signature) - ✗Forgetting that
requires-expressionchecks compilability, not semantic correctness - ✗Wrapping a single concept in
requires (T t) { ... }whenrequires Concept<T>is shorter
Follow-up questions
- →What kinds of clauses can a requires-expression contain (simple, type, compound, nested)?
- →When does subsumption pick one constrained overload over another?
SeniorTheoryCommonWhat is static polymorphism and how is it implemented in C++?
What is static polymorphism and how is it implemented in C++?
Static polymorphism selects behaviour by types known at compile time with zero-cost dispatch. Implemented via overloading, template specialisation, CRTP, if constexpr, and concepts. It cannot hold heterogeneous collections but eliminates vtable indirection.
Common mistakes
- ✗Assuming static polymorphism always produces faster code — the larger code size from template instantiations can cause I-cache pressure
- ✗Choosing CRTP over virtual when the type is not known at compile time
- ✗Conflating
std::variant+std::visit(runtime closed-set polymorphism) with static polymorphism
Follow-up questions
- →When would you choose
std::variant+std::visitover inheritance-based polymorphism? - →What is type erasure and how does
std::functionimplement it?
SeniorTheoryCommonHow do variadic templates work?
How do variadic templates work?
Variadic templates accept any number of type or non-type parameters via a parameter pack (typename... Ts), expanded with .... Recursion was the classical way to process a pack; C++17 fold expressions cover most cases.
Common mistakes
- ✗Incorrect expansion placement — the
...must follow the pattern, not precede it - ✗Not using fold expressions when a simple
(f(args), ...)or(args + ...)would suffice - ✗Mixing parameter packs with non-pack parameters in a confusing order — packs must generally come last
Follow-up questions
- →What are fold expressions and what four forms do they take in C++17?
- →How does
std::tupleuse variadic templates internally?
JuniorTheoryOccasionalCan a constructor be a template function?
Can a constructor be a template function?
Yes — a constructor can be a member function template enabling construction from different argument types. But a templated constructor is never picked as the copy constructor: the compiler always prefers the implicitly generated one.
Common mistakes
- ✗Expecting a templated constructor to serve as the copy constructor — it cannot, because the compiler always generates a real copy constructor that takes precedence
- ✗Forgetting that template argument deduction applies to constructor templates just as to regular function templates
- ✗Using an explicit template constructor without
explicit, causing unintended implicit conversions
Follow-up questions
- →Can you explicitly instantiate a constructor template?
- →How does CTAD (class template argument deduction, C++17) interact with constructor templates?
JuniorTheoryOccasionalCan a virtual function be a template? Why not?
Can a virtual function be a template? Why not?
No — virtual functions cannot be templates. The vtable needs a fixed compile-time size, but a function template can produce an unbounded number of instantiations known only at link time.
Common mistakes
- ✗Confusing a virtual function in a class template (allowed) with a virtual function template member (not allowed)
- ✗Trying to workaround the limitation by templating the whole class — this works but requires knowing all types at definition time
Follow-up questions
- →How can you achieve runtime polymorphism over different types without virtual function templates (type erasure, std::function, std::variant)?
- →What is CRTP and how does it provide compile-time polymorphism?
MiddleTheoryOccasionalHow do C++20 concepts constrain auto parameters and return types?
How do C++20 concepts constrain auto parameters and return types?
Prefixing auto with a concept constrains it: void f(Sortable auto& c) makes the parameter an abbreviated template whose deduced type must satisfy Sortable. The same works on return types: Number auto g();. A mismatch removes the function from overload resolution, not a hard error.
Common mistakes
- ✗Thinking
Sortable autonames a fixed type — it is still a deduced abbreviated-template parameter - ✗Expecting a constraint violation to be a hard error rather than just removing the overload
- ✗Forgetting that each constrained
autointroduces an independent template parameter
Follow-up questions
- →How does an abbreviated function template differ from an explicitly written
template<>one? - →What happens when two constrained overloads both match — how does subsumption decide?
MiddleTheoryOccasionalWhat are class template argument deduction (CTAD) and deduction guides?
What are class template argument deduction (CTAD) and deduction guides?
CTAD (C++17) lets you write std::vector v{1,2,3}; and have the compiler deduce std::vector<int>. Guides are synthesised from constructors; if insufficient, supply user ones like template<class It> Container(It,It) -> Container<typename It::value_type>;.
Common mistakes
- ✗Expecting CTAD to work on aliases pre-C++20 — wasn't supported
- ✗Writing wrong-arity deduction guides and breaking implicit ones
- ✗Forgetting that
auto v = std::vector{1, 2, 3};deduces too — CTAD applies
Follow-up questions
- →What changed for CTAD in C++20 (alias templates)?
- →How does CTAD interact with explicit constructors?
MiddleDebuggingOccasionalWhy are template error messages so long and how do you tame them?
Why are template error messages so long and how do you tame them?
Errors fire deep in the instantiation chain — the compiler prints every step. Tames: C++20 concepts give a one-line 'does not satisfy X', an early static_assert at the call site gives a friendly message, and cppinsights.io helps.
Common mistakes
- ✗Reading errors top-to-bottom instead of starting from your code line
- ✗Ignoring
note:lines that show why the substitution failed - ✗Throwing more SFINAE at the problem instead of refactoring
Follow-up questions
- →How do concepts make errors more actionable?
- →What does
cppinsights.ioshow?
MiddleTheoryOccasionalWhat are alias templates and how do they differ from typedef?
What are alias templates and how do they differ from typedef?
Alias template (template<class T> using Vec = std::vector<T, MyAlloc>;) is a parameterised type name; typedef takes no template parameters. Aliases also avoid typename dependent-name problems. C++20 added CTAD-for-aliases.
Common mistakes
- ✗Trying to write a parameterised typedef — must use alias template
- ✗Forgetting CTAD-for-aliases is C++20 — older code can't deduce through aliases
- ✗Aliasing only the visible part — alias doesn't create new types, just a name
Follow-up questions
- →Why don't aliases create distinct types (vs
struct StrongType { T x; };)? - →How does C++20 CTAD-for-aliases solve which problem?
MiddleTheoryOccasionalWhat is a variable template, and how does it differ from a function or class template?
What is a variable template, and how does it differ from a function or class template?
A variable template (C++14) is a parameterised constant: template<class T> constexpr T pi = T(3.14159);. Each use with a type instantiates a distinct object. Unlike a function template it isn't called; unlike a class template it names a value, not a type.
Common mistakes
- ✗Forgetting
inlineorconstexpron a header variable template — risks ODR violations across TUs - ✗Expecting partial specialization to be disallowed — variable templates do support it, like class templates
- ✗Assuming
pi<int>andpi<double>share storage — each instantiation is a separate object
Follow-up questions
- →How does
std::is_integral_v<T>relate tostd::is_integral<T>::value? - →Can a variable template be partially specialized, and what for?
SeniorTheoryOccasionalWhat is CRTP and what problems does it solve?
What is CRTP and what problems does it solve?
CRTP (Curiously Recurring Template Pattern): Derived inherits from Base<Derived>, letting the base call derived methods via static_cast<Derived*>(this) without virtual dispatch. Used for static polymorphism and mixins.
Common mistakes
- ✗Calling derived methods in the base constructor — the derived object doesn't exist yet
- ✗Forgetting that CRTP does not support heterogeneous collections the way virtual dispatch does
- ✗Letting the base destructor be non-virtual — safe for CRTP since you don't delete via base pointer, but worth noting
Follow-up questions
- →How do C++23
explicit this(deducing this) reduce the need for CRTP? - →Compare CRTP mixins with C++20 concepts for enforcing interfaces.
SeniorDebuggingOccasionalWhy does a name from a dependent base class fail to resolve without this-> or a using-declaration?
Why does a name from a dependent base class fail to resolve without this-> or a using-declaration?
During phase-1 lookup the compiler doesn't search dependent bases, because a specialization could change what Base<T> contains. So an unqualified value is treated as a non-member name and not found. Making it dependent — this->value or Base<T>::value — defers lookup to instantiation, when the base is known.
Common mistakes
- ✗Adding
this->only where the error points, missing other unqualified base names in the same class - ✗Assuming the code is portable because MSVC compiles it — MSVC historically skips strict phase-1 lookup
- ✗Believing a non-dependent base (e.g.
Base<int>) has the same problem — only dependent bases do
Follow-up questions
- →Why do GCC and Clang reject this code while older MSVC accepts it?
- →When would
Base<T>::valuebe preferable tothis->value?
SeniorTheoryOccasionalWhat is the detection idiom and how does std::void_t implement it?
What is the detection idiom and how does std::void_t implement it?
The detection idiom tests at compile time whether an expression such as T::member is well-formed for a type, with no hard error. std::void_t<...> maps any valid types to void, and a partial specialization keyed on void_t<expr> matches only when expr compiles — otherwise a fallback primary template is chosen.
Common mistakes
- ✗Putting the detected expression outside the immediate context, where a failure becomes a hard error instead of a quiet mismatch
- ✗Forgetting the partial specialization's second argument must be exactly
void— a stray non-void default breaks the match - ✗Reaching for the detection idiom in C++20 code where a
requires-expression or concept is far clearer
Follow-up questions
- →How does a C++20
requires-expression replace the detection idiom? - →Why must the detected expression sit in the immediate context?
SeniorTheoryOccasionalWhat is explicit template instantiation and when is it useful?
What is explicit template instantiation and when is it useful?
template class Foo<int>; forces the compiler to instantiate the template here, emitting object code. Pair with extern template in the header so consumers skip implicit instantiation. Speeds builds when many TUs share one instantiation.
Common mistakes
- ✗Using
extern templatewithout providing the explicit instantiation somewhere — link error - ✗Mixing extern template with full-template-definition in headers — easy to break ODR
- ✗Forgetting that explicit instantiation requires the full definition to be visible at the instantiation point
Follow-up questions
- →How does explicit instantiation help shared library ABI stability?
- →What is two-phase name lookup and how does it interact with extern template?
SeniorTheoryOccasionalHow does the compiler process templates (two-phase lookup)?
How does the compiler process templates (two-phase lookup)?
Templates are parsed in two phases. Phase 1, at definition: syntax is checked and non-dependent names are looked up. Phase 2, at instantiation: dependent names are looked up in both the definition and instantiation contexts.
Common mistakes
- ✗Forgetting
typenamebefore a dependent type name — the compiler defaults to treating it as a value, not a type - ✗Forgetting
templatebefore a dependent template name used as a template:obj.template method<T>() - ✗Relying on ADL in phase 2 to find names that should have been found in phase 1
Follow-up questions
- →What is ADL (argument-dependent lookup) and how does it interact with templates?
- →Why might MSVC accept code that GCC and Clang reject regarding two-phase lookup?
SeniorTheoryOccasionalWhat is template metaprogramming?
What is template metaprogramming?
Template metaprogramming (TMP) uses the C++ template system as a compile-time computation engine — types and values via recursive instantiation (classic) or constexpr (modern). <type_traits> is the STL face; C++20 concepts and if constexpr clean it up.
Common mistakes
- ✗Writing deep recursive TMP when
constexpr+ fold expressions achieve the same at a fraction of the complexity - ✗Ignoring compilation time cost — heavy TMP can dramatically slow builds
- ✗Reinventing
<type_traits>primitives instead of composing from the standard library
Follow-up questions
- →How do C++20 concepts replace
std::enable_ifin most cases? - →What is the difference between
constexprand TMP for compile-time computation?
SeniorTheoryOccasionalWhat is tag dispatch and how does it differ from if constexpr or concepts?
What is tag dispatch and how does it differ from if constexpr or concepts?
Tag dispatch selects an overload by passing an empty tag struct conveying a category — the classic STL example is std::distance dispatching on iterator_category. Modern C++ replaces it with if constexpr or concept-constrained overloads.
Common mistakes
- ✗Defining tags without inheritance — limits subsumption (random_access is a forward)
- ✗Using tag dispatch where
if constexpris simpler - ✗Forgetting to declare the tag-receiving overload — caller can't dispatch
Follow-up questions
- →How does iterator_category form a hierarchy via inheritance?
- →When is concept-based dispatch cleaner than tag dispatch?
SeniorTheoryOccasionalHow is recursion implemented in templates, and what replaces it in modern C++?
How is recursion implemented in templates, and what replaces it in modern C++?
Classic TMP used recursive instantiation: a primary template plus base-case specialisation, Factorial<N>::value = N * Factorial<N-1>::value; with Factorial<0>::value = 1. Modern C++ replaces this with if constexpr and consteval.
Common mistakes
- ✗Deeply recursive templates blowing up compile time and memory
- ✗Forgetting to specialise the base case — infinite recursion at compile time
- ✗Using recursive templates where fold expressions or
constevalare simpler
Follow-up questions
- →How would you implement compile-time fibonacci with
consteval? - →Why is template recursion considered slow at compile time?
SeniorTheoryOccasionalWhen and why do you need typename and template disambiguators inside templates?
When and why do you need typename and template disambiguators inside templates?
Inside a template the compiler can't tell whether a dependent name is a type, value, or template — it defaults to value. typename T::nested declares a type; t.template foo<int>() declares a template. C++20 made typename optional where context implies a type.
Common mistakes
- ✗Forgetting
typenameand getting cryptic 'expected primary-expression' errors - ✗Forgetting
.templatewhen calling a templated method on a dependent object - ✗Adding
typenamewhere it's not needed — pre-C++20 this was harmless; in C++20 it might be wrong
Follow-up questions
- →Where exactly did C++20 make
typenameoptional? - →Why does the parser need these hints at all?
SeniorPerformanceRareWhat does extern template do and how does it speed up compilation?
What does extern template do and how does it speed up compilation?
extern template class Foo<int>; in a header suppresses implicit instantiation in every including TU; one .cpp provides the body via template class Foo<int>;. Avoids redoing parsing and codegen in every TU.
Common mistakes
- ✗Putting
extern templatewithout the matching explicit instantiation — link error - ✗Forgetting that
extern templateonly suppresses implicit instantiation - ✗Adding
extern templatefor a templated function in a header that other TUs might inline
Follow-up questions
- →How does
extern templateinteract with header-only libraries? - →Why does the standard library use
extern templatefor common instantiations?
SeniorTheoryRareHow does the compiler pick the most specialized template among competing candidates?
How does the compiler pick the most specialized template among competing candidates?
Partial ordering ranks templates by specificity: A is more specialized than B if every argument set matching A also matches B but not the reverse. The compiler checks this by deducing each candidate's parameters from the other's, and the one-way-deducible candidate wins. It applies to both class partial specializations and function overloads.
Common mistakes
- ✗Assuming declaration order decides the winner — partial ordering is purely by specificity, not position
- ✗Writing two partial specializations where neither is more specialized than the other, producing an ambiguity error
- ✗Expecting function-template partial ordering to behave like class partial specialization — functions use overloading instead
Follow-up questions
- →Why can two partial specializations be mutually ambiguous?
- →How does partial ordering interact with concept subsumption in C++20?
SeniorTheoryRareHow do you declare a template friend correctly inside a class?
How do you declare a template friend correctly inside a class?
Three forms: (1) befriend one instantiation — friend void f<int>(MyClass&);; (2) befriend the whole template — template<class T> friend void f(MyClass&);; (3) define a non-template friend inside the class body — the pattern for operator<< so ADL finds it.
Common mistakes
- ✗Friending one instantiation thinking it grants access to all
- ✗Defining
operator<<outside a class template — name lookup fails because the function is never declared as non-friend - ✗Forgetting
template<>syntax for friending a specific instantiation
Follow-up questions
- →Why does
operator<<for class templates often need to be defined inside the class? - →How does ADL find friend functions?
SeniorTheoryRareWhat is a template template parameter and where is it useful?
What is a template template parameter and where is it useful?
A template template parameter takes a template, not a type: template<template<typename> class C> struct Wrap { C<int> v; };. Useful for code that re-instantiates a generic container with different element types — e.g. allocator policies.
Common mistakes
- ✗Forgetting that the inner template arity must match what you instantiate with
- ✗Using
classfor the inner keyword pre-C++17 — onlyclasswas valid; now both work - ✗Confusing template template params with variadic template templates
Follow-up questions
- →How would you accept
std::vectorandstd::listinterchangeably? - →Can a template template parameter take
auto?