Where and why do I have to put the "template" and "typename" keywords?
In C++ templates, the keywords "template" and "typename" are used to provide hints to the compiler in certain situations where it may not be able to deduce the correct meaning of a dependent name.
Dependent Names
A dependent name is a name that depends on a template parameter or a base class. In the given code example, the name "inUnion" is a dependent name because it depends on the template parameter "Tail".
Using "typename" with Dependent Names
When referring to a dependent name that represents a type, you need to use the "typename" keyword to inform the compiler that it is indeed a type. This is necessary because the compiler cannot assume that a dependent name is a type by default.
template <typename T, typename Tail>
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
// "typename" is required here
typedef typename Tail::inUnion<U> dummy;
};
template< > struct inUnion<T> { };
};
In the above code snippet, "typename" is used before "Tail::inUnion" to indicate that "inUnion" is a type. Without "typename", the compiler would assume that "inUnion" is a static member variable or function, leading to a compilation error.
Using "template" with Dependent Names
When a dependent name represents a template, you need to use the "template" keyword before it. This is necessary to disambiguate between dependent names that are templates and those that are not.
template <typename T, typename Tail>
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
// Use "template" here to indicate that "inUnion" is a template
template <typename V>
struct nested {
// ...
};
};
};
In the code snippet above, "template" is used before "inUnion" inside the nested structure to indicate that "inUnion" is a template. Without "template", the compiler would assume that "inUnion" is a nested class, leading to a compilation error.
Putting it all together
Based on the given code example, the correct usage of "typename" and "template" would be:
template <typename T, typename Tail>
struct UnionNode : public Tail {
// ...
template <typename U> struct inUnion {
// Using both "typename" and "template" here
typedef typename Tail::template inUnion<U> dummy;
};
template< > struct inUnion<T> { };
};
template <typename T>
struct UnionNode<T, void> {
// ...
template<typename U> struct inUnion;
template< > struct inUnion<T> { };
};
By using both "typename" and "template" in the appropriate places, you can ensure that the compiler correctly interprets the dependent names in your code and avoids any compilation errors related to their usage.