Question
Dependent Names, typename, and template in C++ Templates
Question
In C++ templates, when and why do you need to write typename and template for dependent names?
What exactly is a dependent name?
For example, consider this code:
template <typename T, typename Tail> // Tail will also be a UnionNode.
struct UnionNode : public Tail {
template <typename U>
struct inUnion {
// Where should typename/template be added here?
typedef Tail::inUnion<U> dummy;
};
template <>
struct inUnion<T> { };
};
template <typename T> // For the last node Tn.
struct UnionNode<T, void> {
template <typename U>
struct inUnion; // intentionally not defined
template <>
struct inUnion<T> { };
};
The issue is with this line:
typedef Tail::inUnion<U> dummy;
It seems that inUnion is a dependent name, so the compiler cannot know immediately what it refers to. I understand that template can be used to tell the compiler that inUnion is a template, but where exactly should it go?
Also, if template is used, does that automatically mean inUnion<U> is treated as a type rather than a function or something else?
Short Answer
By the end of this page, you will understand what dependent names are in C++, why the compiler sometimes needs extra help inside templates, and exactly when to use the typename and template keywords. You will also see how to fix expressions like Tail::inUnion<U> correctly and learn the common rules developers use in real template code.
Concept
In C++, templates are parsed in two phases:
- Phase 1: the compiler parses the template before knowing the actual template arguments.
- Phase 2: the compiler instantiates the template later, when real types are substituted.
Because of this, some names inside a template depend on a template parameter and cannot be fully understood during the first phase. These are called dependent names.
A name is dependent if its meaning depends on a template parameter. For example:
Tail::inUnion<U>
Here, Tail is a template parameter, so the compiler does not yet know what members Tail has. That means:
- it does not know whether
inUnionis a type, function, variable, or template - it cannot safely parse
<U>as template arguments unless you tell it to
This is why C++ provides two disambiguation keywords:
typenametells the compiler: this dependent qualified name is a typetemplatetells the compiler: this dependent qualified name is a template
For your example, the correct form is:
typedef typename Tail:: inUnion<U> dummy;
Mental Model
Think of the compiler as reading a sentence with missing dictionary entries.
If it sees this:
Tail::inUnion<U>
it thinks:
- “I do not know what
Tailis yet.” - “So I do not know what
inUnionmeans here.” - “That
<U>might be template arguments... or it might be a less-than operator.” - “I also do not know whether the whole thing is a type.”
So you must label it clearly:
template= “parse the following name as a template”typename= “treat the result as a type”
A simple analogy:
templateis like saying: this is a generic blueprinttypenameis like saying: the thing produced here is a type name
Without those labels, the compiler refuses to guess in dependent contexts.
Syntax and Examples
Core rule
When you refer to a member template through a dependent type, write:
typename DependentType::template MemberTemplate<Args...>
When you refer to a nested type through a dependent type, write:
typename DependentType::NestedType
Your example fixed
template <typename T, typename Tail>
struct UnionNode : public Tail {
template <typename U>
struct inUnion {
typedef typename Tail::template inUnion<U> dummy;
};
};
This says:
Tail::...depends onTailinUnionis a templateinUnion<U>is a type
Example: dependent nested type
Step by Step Execution
Consider this example:
template <typename Tail>
struct Node {
template <typename U>
struct inner {
using type = U;
};
template <typename U>
void test() {
typename Tail::template inner<U> value;
}
};
Step-by-step
- The compiler starts parsing
Node<Tail>. - It sees
Tail::template inner<U>insidetest(). Tailis a template parameter, so the compiler does not know its real type yet.- Therefore,
Tail::inneris a dependent name. - Without help, the compiler cannot know whether
inneris:- a type
- a static member
- a function
- a template
- The
templatekeyword tells the compiler thatinneris a template.
Real World Use Cases
Dependent names appear often in real C++ code, especially in generic libraries.
1. Standard-library style generic code
template <typename Container>
void process(const Container& c) {
typename Container::const_iterator it = c.begin();
}
Used when writing functions that work with many container types.
2. Traits and type transformations
template <typename Traits>
using value_type_t = typename Traits::value_type;
Common in type traits, allocators, iterators, and metaprogramming helpers.
3. Rebinding or nested templates
template <typename Alloc>
using int_alloc = typename Alloc::template rebind<int>::other;
Older allocator patterns and some generic libraries use this style.
4. CRTP and policy-based design
template < Policy>
: Policy {
{
Policy::config cfg;
}
};
Real Codebase Usage
In real projects, developers usually encounter these rules in a few repeatable patterns.
Guarding dependent types with aliases
Instead of repeatedly writing long dependent names, developers often create aliases:
template <typename Tail>
struct Node {
template <typename U>
using inner_t = typename Tail::template inner<U>;
};
This improves readability and reduces mistakes.
Validation through traits
Template code often checks whether a nested type or member template exists:
template <typename T>
using value_type_t = typename T::value_type;
This is common in generic utilities and library internals.
Early clarification in complex declarations
When a declaration is hard to read, developers put the type into a using declaration first:
template <typename Tail>
struct Node {
template < U>
{
inner_type = Tail:: inner<U>;
inner_type x;
}
};
Common Mistakes
1. Forgetting typename for a dependent type
Broken code:
template <typename T>
void f() {
T::value_type x;
}
Correct:
template <typename T>
void f() {
typename T::value_type x;
}
Why: T::value_type depends on T, so the compiler needs to be told that it is a type.
2. Forgetting template for a dependent member template
Broken code:
template <typename T>
void f() {
typename T::rebind<int>::other x;
}
Correct:
< T>
{
T:: rebind<>::other x;
}
Comparisons
| Situation | Example | Need typename? | Need template? | Why |
|---|---|---|---|---|
| Dependent nested type | T::value_type | Yes | No | It is a type, but not a template |
| Dependent member template naming a type | T::rebind<int> | Yes | Yes | It is both a template and a type |
| Dependent member template function call | obj.foo<int>() | No | Yes, as obj.template foo<int>() | It is a template call, not a type |
| Non-dependent nested type |
Cheat Sheet
Quick rules
- A dependent name is a name whose meaning depends on a template parameter.
- Use
typenamewhen a dependent qualified name refers to a type. - Use
templatewhen a dependent qualified name refers to a template. - Sometimes you need both.
Common patterns
typename T::value_type
typename T::template rebind<int>
obj.template func<int>()
Your case
typedef typename Tail::template inUnion<U> dummy;
Meaning of each keyword
typename=> “this is a type”template=> “this is a template”
When typename is not needed
FAQ
What is a dependent name in C++?
A dependent name is a name whose meaning depends on a template parameter. For example, T::value_type depends on what T actually is.
Why does C++ need typename?
Because when parsing a template, the compiler cannot always know whether a dependent qualified name refers to a type. typename removes that ambiguity.
Why does C++ need the template keyword?
Because the compiler cannot always tell whether a dependent member name followed by <...> is a template or something else. template tells it to parse the name as a template.
Do I always need both typename and template?
No. You use:
- only
typenamefor dependent types that are not templates - only
templatefor dependent template function calls - both when a dependent member template names a type
What is the correct fix for Tail::inUnion<U>?
Use:
Mini Project
Description
Build a small type-traits-style utility that checks whether a container-like type provides a nested value_type and a nested member template rebind<U>. This project demonstrates both forms of disambiguation: using typename for dependent nested types and template for dependent member templates.
Goal
Create a C++ program that successfully accesses a dependent nested type and a dependent member template using the correct syntax.
Requirements
- Define a type with a nested
value_typealias. - Define a member template
rebind<U>inside that type. - Write a generic function or alias that accesses
value_typethrough a template parameter. - Write another generic alias that accesses
rebind<int>through a template parameter. - Compile and print a small result to prove the types were resolved correctly.
Keep learning
Related questions
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++ Casts Explained: C-Style Cast vs static_cast vs dynamic_cast
Learn the difference between C-style casts, static_cast, and dynamic_cast in C++ with clear examples, safety rules, and real usage tips.
C++ Lambda Expressions Explained: What They Are and When to Use Them
Learn what C++ lambda expressions are, why they exist, when to use them, and how they simplify callbacks, algorithms, and local logic.