template and typename in C++: where to put them and why you can't do without them
\n\nIf you've ever written or read C++ code with templates, you've probably encountered a situation where the compiler suddenly throws an error for no apparent reason. You're sure the code is correct, but the compiler stubbornly demands a template or typename. Sound familiar? Welcome to the club.
This question is one of the most popular on Stack Overflow (thousands of views and dozens of answers). And it's no wonder: even experienced developers sometimes get confused about where to use these keywords. In this article, we'll figure it out once and for all: where, when, and why you need to write template and typename in C++. And most importantly, we'll understand how to avoid the trap.
Why did this problem even arise?
\n\nThe root of the evil lies in dependent names. When you write template code, the compiler cannot immediately tell what it's dealing with: a type or something else. This is because the template parameters are not yet known. The compiler postpones parsing until instantiation, but it needs to know the syntactic role of the name already at the initial parsing stage.
\n\nImagine you write:
\n\ntemplate<typename T>\nvoid foo() {\n T::something * p;\n}\n\n\nWhat is this? A declaration of a pointer p to T::something? Or a multiplication of T::something by p? Without additional information, the compiler doesn't know. And it is precisely to resolve this ambiguity that the keywords typename and template were introduced.
The typename keyword: when the type is not obvious
\n\nThe main rule
\n\nThe keyword typename is used to tell the compiler: "Hey, what comes next is a type, not something else". It is needed in cases where the name depends on a template parameter, and the compiler cannot independently determine that it is a type.
Consider a classic example:
\n\ntemplate<typename T>\nclass MyClass {\npublic:\n // Without typename — compilation error\n typename T::value_type getValue() const {\n return data;\n }\nprivate:\n T data;\n};\n\n\nHere, T::value_type is a dependent name. Without typename, the compiler would think that value_type is a static data member or a nested class, but not a type. But we know it's a type (for example, int, if T is std::vector<int>).
Where else is typename needed?
\n\nThe rule is simple: typename is required before dependent type names in the following contexts:
- \n
- In variable and class member declarations \n
- In function parameters \n
- In return types \n
- In using declarations (type aliases) \n
- In base classes (if the base class is a dependent type) \n
Example with using:
\n\ntemplate<typename T>\nclass Container {\n using Iterator = typename T::iterator; // typename is mandatory!\n // ...\n};\n\n\nWhen is typename NOT needed?
\n\nThere are important exceptions where typename is not required:
- \n
- In the template parameter list:
template<typename T>— heretypenameis part of the syntax \n - In base classes:
class Derived : public Base<T>::Nested— heretypenameis not needed \n - In the constructor initializer list \n
- In a context where the name is explicitly a type (for example, after
new) \n
The template keyword: when a template is inside a template
\n\nThe essence of the problem
\n\nThe situation with template is mirrored. It is needed when you access a template member of a dep