Question

typename vs class in C++ Templates: What’s the Difference?

cpptemplateskeyword

Question

In C++ templates, I have seen both of these declarations:

template <typename T>
template <class T>

What is the difference between them?

Also, what do these keywords mean in the following example?

template <template <typename, typename> class Container, typename Type>
class Example
{
    Container<Type, std::allocator<Type>> baz;
};

I want to understand when typename and class mean the same thing, and when they serve different purposes in template syntax.

Short Answer

By the end of this page, you will understand that in a template parameter list, typename and class usually mean the same thing when introducing a type parameter. You will also learn the important exception: typename has another role in C++ for disambiguating dependent names. The nested template example will make sense step by step, including how a template template parameter works.

Concept

In C++, both typename and class can be used to declare a type template parameter.

For example, these are equivalent:

template <typename T>
class Box;

template <class T>
class Box;

In both cases, T stands for a type such as int, std::string, or a user-defined class.

When they mean the same thing

Inside a template parameter list, typename and class are interchangeable for naming a type parameter:

template <typename T>
void func(T value);

template <class T>
void func(T value);

Both say: “this template takes a type parameter named T.”

Why two keywords exist

Historically, class was the original keyword used for type template parameters. Later, typename was added because it is clearer: the parameter can be any type, not just a class.

For example, this is valid:

template <typename T>
T add(T a, T b) {
    return a + b;
}

int result = add<int>(2, 3);

int is not a class, but it is still a type.

The important difference

Outside the template parameter list, typename has an additional meaning that class does not have.

It is used to tell the compiler that a dependent name refers to a type.

Example:

template <typename T>
void print_first(const T& container) {
    typename T::const_iterator it = container.begin();
}

Here, T::const_iterator depends on T. The compiler cannot know in advance whether const_iterator is a type or something else, so typename is required.

You cannot write:

class T::const_iterator it;

That would be invalid.

So the rule is:

  • In a template parameter list, typename and class are usually equivalent.
  • In other places, typename can be required to mark a dependent type name.
  • class cannot be used for that purpose.

Understanding the example

Consider this template:

template <template <typename, typename> class Container, typename Type>
class Example
{
    Container<Type, std::allocator<Type>> baz;
};

This declares a class template named Example with two template parameters:

  1. Container
  2. Type

typename Type

This part is simple:

typename Type

It means Type is a type parameter.

For example:

Example<std::vector, int>

Here, Type becomes int.

template <typename, typename> class Container

This is a template template parameter. That means Container is not a type itself. It is a template that takes two type parameters.

So Container could be something like std::vector in older-style examples, or another container template that matches that shape.

This part:

template <typename, typename> class Container

means:

  • Container must be a class template
  • that class template must accept two type parameters

Then inside Example, it is used like this:

Container<Type, std::allocator<Type>> baz;

So if Container is std::vector and Type is int, then baz becomes:

std::vector<int, std::allocator<int>> baz;

Why this matters

This syntax is useful when you want to write reusable code that works with a family of templates, not just one specific type. It appears in generic libraries, wrappers, allocators, and policy-based designs.

Mental Model

Think of a template like a form with blanks to fill in.

  • typename T or class T means: “fill this blank with a type.”
  • template <typename, typename> class Container means: “fill this blank with a template that itself needs two type blanks.”

So there are two levels:

  1. A blank for a normal type, like int
  2. A blank for a template, like std::vector

A simple analogy:

  • typename T is like asking for a material: wood, steel, plastic
  • template <typename, typename> class Container is like asking for a blueprint that can build something once you provide materials

Then this line:

Container<Type, std::allocator<Type>> baz;

says: use the blueprint Container, fill in the type Type and an allocator, and create an object named baz.

Take Quiz

Syntax and Examples

Basic syntax

Type template parameter using typename

template <typename T>
class Box {
public:
    T value;
};

Type template parameter using class

template <class T>
class Box {
public:
    T value;
};

These mean the same thing.

Example: both forms are equivalent

#include <iostream>

template <typename T>
T square1(T x) {
    return x * x;
}

template <class T>
T square2(T x) {
    return x * x;
}

int main() {
    std::cout << square1<int>(4) << '\n';
    std::cout << square2<int>(5) << '\n';
}

Both functions work the same way.

Example where typename is required

#include <vector>

template <typename T>
void showFirst(const T& container) {
    typename T::const_iterator it = container.begin();
}

Why?

T::const_iterator depends on T. The compiler needs help to know it is a type.

Template template parameter example

#include <vector>
#include <memory>

template <template <typename, typename> class Container, typename Type>
class Example {
public:
    Container<Type, std::allocator<Type>> baz;
};

int main() {
    Example<std::vector, int> ex;
    ex.baz.push_back(42);
}

Explanation

  • Container must be a template taking two type arguments
  • Type is a regular type parameter
  • baz becomes std::vector<int, std::allocator<int>>

Modern style note

Many C++ developers prefer typename for type template parameters because it reads more clearly. But class is still correct and common.

Step by Step Execution

Consider this example:

#include <vector>
#include <memory>

template <template <typename, typename> class Container, typename Type>
class Example {
public:
    Container<Type, std::allocator<Type>> baz;
};

int main() {
    Example<std::vector, int> ex;
    ex.baz.push_back(10);
    ex.baz.push_back(20);
}

Step-by-step

1. The template is declared

template <template <typename, typename> class Container, typename Type>

This says Example needs:

  • Container: a class template that takes two type parameters
  • Type: a normal type

2. main() creates an instance

Example<std::vector, int> ex;

Now substitute:

  • Container = std::vector
  • Type = int

3. The member declaration is expanded

Inside the class, this:

Container<Type, std::allocator<Type>> baz;

becomes:

std::vector<int, std::allocator<int>> baz;

4. The object is constructed

ex now contains a vector of integers named baz.

5. Values are added

ex.baz.push_back(10);
ex.baz.push_back(20);

The vector stores 10 and 20.

Key takeaway

The outer template Example accepts another template (std::vector) as an argument, then uses it to build a concrete type.

Real World Use Cases

Generic containers and wrappers

You may want a class to work with different container templates:

  • std::vector
  • std::list
  • custom container templates

Reusable library components

Library code often accepts types and templates as parameters so the user can customize behavior without rewriting logic.

Allocator-aware code

The example uses std::allocator<Type>, which is relevant in codebases that care about memory allocation strategy.

Policy-based design

A class may accept templates that define behavior, storage, or configuration.

Generic algorithms

Understanding typename is essential when writing algorithms that depend on nested types such as:

  • T::value_type
  • T::iterator
  • T::const_iterator

Example:

template <typename Container>
typename Container::value_type lastValue(const Container& c) {
    return c.back();
}

Here, typename is needed because Container::value_type is a dependent type.

Take Quiz

Real Codebase Usage

In real C++ projects, developers use these ideas in a few common ways.

1. Generic type parameters

This is the most common usage:

template <typename T>
class Result {
    T value;
};

This appears in utility classes, containers, wrappers, and algorithms.

2. Dependent nested types

This is extremely common in generic code:

template <typename Container>
void process(const Container& c) {
    typename Container::const_iterator it = c.begin();
    (void)it;
}

3. Validation through template shape

Template template parameters let APIs require a specific template form:

template <template <typename, typename> class Seq, typename T>
class Buffer {
    Seq<T, std::allocator<T>> data;
};

4. Early constraints by interface shape

Even before modern concepts, developers used template signatures to restrict what kinds of templates were accepted.

5. Readability conventions

Teams often choose one style consistently:

  • use typename for type parameters
  • use class only when defining actual classes

This is a style choice, not a rule.

6. Error handling in templates

Template code often produces confusing compiler errors. Clear naming helps:

template <typename ValueType>
class Storage;

Using descriptive names can make template-heavy code easier to read and debug.

Common Mistakes

Mistake 1: Thinking class means only user-defined classes

Wrong idea:

template <class T>
T add(T a, T b);

Some beginners think T must be a class type. That is false.

This works with built-in types too:

add<int>(1, 2);

Mistake 2: Forgetting typename for dependent types

Broken code:

template <typename T>
void f() {
    T::value_type x;
}

Fix:

template <typename T>
void f() {
    typename T::value_type x;
}

Why: the compiler needs to know T::value_type is a type.

Mistake 3: Trying to use class where only typename works

Broken code:

template <typename T>
void f() {
    class T::value_type x;
}

This is invalid C++.

Mistake 4: Misreading template template parameters

Broken assumption:

template <template <typename, typename> class Container, typename Type>
class Example;

This does not mean Container is an object or a regular type. It is itself a template.

Mistake 5: Passing a template with the wrong parameter shape

If the template parameter expects two type parameters, the supplied template must match.

Example shape expected:

template <typename, typename>
class Something;

If you pass a template with a different signature, compilation can fail.

Mistake 6: Assuming all containers match the same template form

Not every container template has exactly the same template parameters or defaults in every context. Always check the actual template declaration.

Comparisons

ConceptMeaningWhere usedNotes
typename TT is a type parameterTemplate parameter listsEquivalent to class T here
class TT is a type parameterTemplate parameter listsHistorical syntax; still valid
typename T::value_typeT::value_type is a typeInside template definitionstypename may be required
class T::value_typeInvalid in this contextNot usedclass cannot replace typename here

typename vs class in template parameter lists

FormValid?Meaning
template <typename T>YesType parameter
template <class T>YesType parameter

typename in other contexts

FormValid?Why
typename T::iterator it;YesMarks dependent type
T::iterator it;Often noCompiler may not know it is a type
class T::iterator it;NoWrong keyword

Type parameter vs template template parameter

SyntaxWhat it acceptsExample
typename TA typeint, std::string
template <typename, typename> class CA class template with two type parametersstd::vector in this example style
Take Quiz

Cheat Sheet

Quick rules

  • In a template parameter list, typename and class usually mean the same thing.
  • Both can declare a type parameter.
  • typename is also used elsewhere to mark a dependent name as a type.
  • class cannot be used for that second purpose.

Equivalent forms

template <typename T>
class A;

template <class T>
class A;

When typename is required

template <typename T>
void f() {
    typename T::value_type x;
}

Template template parameter syntax

template <template <typename, typename> class Container, typename T>
class Example {
    Container<T, std::allocator<T>> data;
};

Read this as

  • typename T → T is a type
  • class T → T is a type
  • template <...> class Container → Container is a template

Common style guideline

Many developers prefer:

  • typename for template type parameters
  • class for actual class declarations

But this is style, not a language rule.

Key exception to remember

This is valid:

typename T::iterator it;

This is not:

class T::iterator it;

FAQ

Is there any difference between typename and class in template <...>?

In a template parameter list for a type parameter, no. They mean the same thing.

Should I prefer typename or class in C++ templates?

Many developers prefer typename because it is clearer that the parameter can be any type, not just a class. But both are correct.

Why does typename sometimes appear before T::value_type?

Because T::value_type is a dependent name. The compiler needs typename to know it refers to a type.

Can I use class instead of typename before T::value_type?

No. That use is specific to typename.

What is a template template parameter?

It is a template parameter that accepts another template as an argument.

What does template <template <typename, typename> class Container> mean?

It means Container must be a class template that takes two type parameters.

Does template <class T> mean T must be a class type?

No. T can be any type, including int, double, pointers, or user-defined types.

Why is std::allocator<Type> used in the example?

Because the Container template is expected to take two type arguments, and many standard containers use the second one as an allocator type.

Take Quiz

Mini Project

Description

Build a small generic wrapper class that can store values inside a container template such as std::vector. This project demonstrates two key ideas from the question: regular type template parameters and template template parameters. It also helps you read and write nested template syntax with more confidence.

Goal

Create a reusable class that accepts a container template and a value type, stores values, and prints the number of stored items.

Requirements

  1. Create a class template that accepts a container template and a type parameter.
  2. Store data using the provided container with std::allocator.
  3. Add a method to insert values into the container.
  4. Add a method to return the number of stored elements.
  5. Instantiate the class with std::vector and int in main().
Take Quiz

Keep learning

Related questions

View more