Question
When declaring a function template or class template in C++, both of these forms are valid:
template <class T>
// ...
template <typename T>
// ...
Is there a good reason to prefer class over typename, or vice versa? Are there situations where the two keywords behave differently?
Short Answer
In a normal C++ type template parameter, class and typename mean exactly the same thing. Either keyword can introduce a parameter that will represent a type. The choice is usually a matter of team style and readability. However, typename has another important use in C++: telling the compiler that a dependent qualified name is a type.
Concept
A template lets you write code that works with many types. For example, a Box<T> can store an int, a std::string, or a custom type.
When declaring a type template parameter, C++ accepts either of these declarations:
template <class T>
class Box;
// Equivalent:
template <typename T>
class Box;
In this position, class does not mean that T must be a class. T may be any type, including fundamental types such as int, pointer types, enums, or class types.
template <class T>
class Box {
public:
T value;
};
Box<int> number{42};
Box<double> price{19.99};
So, for ordinary type parameters, neither keyword provides extra capability. Consistency within a project is usually the best reason to choose one.
Mental Model
Think of a template parameter as a blank label on a box:
template <class T>
and
template <typename T>
both mean: “Create a blank label named T; later, someone will fill it with a type.” The two labels do the same job.
The word typename has a second job in template code. Imagine the compiler sees T::item. Until it knows what T is, it cannot tell whether item is a type or a value. Writing typename T::item is like attaching a note that says: “Treat item as a type.”
Syntax and Examples
A type parameter can be declared with either keyword.
#include <iostream>
// `class` and `typename` are equivalent here.
template <class T>
T larger(T left, T right) {
return left > right ? left : right;
}
template <typename T>
class Holder {
public:
explicit Holder(T initialValue) : value(initialValue) {}
T get() const {
return value;
}
private:
T value;
};
int main() {
std::cout << larger(4, 9) << '\n';
Holder<double> temperature(21.5);
std::cout << temperature.get() << '\n';
}
larger uses class T, while uses . Both parameters stand for a type.
Step by Step Execution
Consider this function template:
template <typename T>
T add(T left, T right) {
return left + right;
}
int result = add(3, 4);
Execution and compilation happen as follows:
-
template <typename T>declaresTas a placeholder for a type. -
The call
add(3, 4)supplies twointarguments. -
The compiler deduces that
Tisint. -
It produces an
intversion of the function conceptually equivalent to:int add(int left, int right) { return left + right; } -
The function returns , which is stored in .
Real World Use Cases
Type template parameters are common throughout C++ code:
- Containers:
std::vector<T>,std::optional<T>, andstd::unique_ptr<T>need a type to store or manage. - Generic algorithms: A function can work with different number types, iterators, or user-defined objects.
- Serialization: A template can save and load objects of multiple supported types.
- Library wrappers: A
Result<T>orCache<T>type can expose the same interface for many value types. - Traits and aliases: Template code often obtains a nested type such as
Traits<T>::value_type, where dependent-nametypenamemay be required.
For example, a generic API response wrapper may use either parameter keyword:
template <typename T>
struct ApiResponse {
int statusCode;
T data;
};
ApiResponse<std::string> response{200, "ok"};
Real Codebase Usage
In production code, the choice between class and typename in a type parameter is commonly governed by a style guide.
Common patterns include:
- Use
typenamefor all type parameters because it makes the intent explicit: the parameter represents a type. - Use
classfor type parameters because it is shorter and traditional in generic C++ code. - Use
classin template declarations but reservetypenamefor dependent qualified types, making the special disambiguation easier to notice.
For example, this generic validation function uses an early return and a dependent nested type:
#include <stdexcept>
template <class Container>
typename Container::value_type firstOrThrow(const Container& items) {
if (items.empty()) {
throw std::runtime_error("Container is empty");
}
return *items.begin();
}
class Container declares a type parameter. has the different job of identifying a dependent nested type.
Common Mistakes
Thinking class T accepts only classes
This is incorrect. It accepts any type.
template <class T>
T identity(T value) {
return value;
}
int count = identity(10); // Valid: T is int
Expecting a behavioral difference in ordinary type parameters
These declarations are equivalent:
template <class T> void process(T value);
template <typename T> void process(T value);
Do not choose one expecting different overload resolution, generated code, or performance.
Forgetting typename for a dependent nested type
The following is typically ill-formed because the compiler does not know whether T::value_type is a type:
Comparisons
| Situation | class | typename | Notes |
|---|---|---|---|
| Ordinary type template parameter | Yes | Yes | Equivalent. |
| Function template type parameter | Yes | Yes | Equivalent. |
| Class template type parameter | Yes | Yes | Equivalent. |
Dependent qualified type, such as T::value_type | No | Yes | typename may be required to identify it as a type. |
Non-type template parameter, such as int N | No | No |
Cheat Sheet
// Equivalent type parameter declarations
template <class T>
struct A {};
template <typename T>
struct B {};
- In a type template parameter,
classandtypenamehave the same meaning. class Tdoes not restrictTto class types.- Choose one based on your codebase's style guide.
typenamealso disambiguates a dependent qualified type:
template <class T>
using Value = typename T::value_type;
- Do not use either keyword for a non-type parameter:
template <int N>
struct FixedSizeArray {};
- Historical note: before C++17, template template parameter inner type parameters required
class, not .
FAQ
Is template<class T> faster than template<typename T>?
No. They are equivalent for normal type template parameters and produce no performance difference.
Should I use class or typename in modern C++?
Either is correct. Follow the existing style of the project or team. Many developers prefer typename because it reads clearly as “this is a type.”
Does class T mean that T must be an object-oriented class?
No. T can be int, double, an enum, a pointer, a class, or another valid type.
Why does C++ sometimes require typename?
Inside a template, a name such as T::value_type depends on T. typename tells the compiler that this dependent name is a type.
Can I replace every typename with class?
No. They are interchangeable only when declaring a type template parameter. In , only performs the required disambiguation.
Mini Project
Description
Build a small generic utility that returns the first value from a container and demonstrates both meanings of typename: declaring a type parameter and identifying a dependent nested type. This pattern resembles helper functions used in data-processing and library code.
Goal
Create a reusable firstOrDefault function that works with standard containers and returns their element type.
Requirements
- Declare the container parameter as a template type parameter.
- Return the container's
value_type. - Return a caller-provided default value when the container is empty.
- Demonstrate the function with
std::vector<int>andstd::list<std::string>. - Use
typenamecorrectly for the dependentvalue_type.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.