In templates, where and why do I have to put typename and template on dependent names?
What exactly are dependent names anyway?
I have the following code:
template <typename T, typename Tail> // Tail will be a UnionNode too.
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
// Q: where to add typename/template 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> { }; // specialization only for T
};
The problem I have is in the typedef Tail::inUnion<U> dummy line. I'm fairly certain that inUnion is a dependent name, and VC++ is quite right in choking on it.
I also know that I should be able to add template somewhere to tell the compiler that inUnion is a template-id, but where exactly? Should it then assume that inUnion is a class template, i.e. inUnion<U> names a type and not a function?
(See here also for my C++11 answer)
In order to parse a C++ program, the compiler needs to know whether certain names are types or not. The following example demonstrates that:
How should this be parsed? For many languages a compiler doesn't need to know the meaning of a name in order to parse and basically know what action a line of code does. In C++, the above however can yield vastly different interpretations depending on what
tmeans. If it's a type, then it will be a declaration of a pointerf. However if it's not a type, it will be a multiplication. So the C++ Standard says at paragraph (3/7):How will the compiler find out what a name
t::xrefers to, iftrefers to a template type parameter?xcould be a static int data member that could be multiplied or could equally well be a nested class or typedef that could yield to a declaration. If a name has this property - that it can't be looked up until the actual template arguments are known - then it's called a dependent name (it "depends" on the template parameters).You might recommend to just wait till the user instantiates the template:
This will work and actually is allowed by the Standard as a possible implementation approach. These compilers basically copy the template's text into an internal buffer, and only when an instantiation is needed, they parse the template and possibly detect errors in the definition. But instead of bothering the template's users (poor colleagues!) with errors made by a template's author, other implementations choose to check templates early on and give errors in the definition as soon as possible, before an instantiation even takes place.
So there has to be a way to tell the compiler that certain names are types and that certain names aren't.
The "typename" keyword
The answer is: We decide how the compiler should parse this. If
t::xis a dependent name, then we need to prefix it bytypenameto tell the compiler to parse it in a certain way. The Standard says at (14.6/2):There are many names for which
typenameis not necessary, because the compiler can, with the applicable name lookup in the template definition, figure out how to parse a construct itself - for example withT *f;, whenTis a type template parameter. But fort::x * f;to be a declaration, it must be written astypename t::x *f;. If you omit the keyword and the name is taken to be a non-type, but when instantiation finds it denotes a type, the usual error messages are emitted by the compiler. Sometimes, the error consequently is given at definition time:The syntax allows
typenameonly before qualified names - it is therefor taken as granted that unqualified names are always known to refer to types if they do so.A similar gotcha exists for names that denote templates, as hinted at by the introductory text.
The "template" keyword
Remember the initial quote above and how the Standard requires special handling for templates as well? Let's take the following innocent-looking example:
It might look obvious to a human reader. Not so for the compiler. Imagine the following arbitrary definition of
boost::functionandf:That's actually a valid expression! It uses the less-than operator to compare
boost::functionagainst zero (int()), and then uses the greater-than operator to compare the resultingboolagainstf. However as you might well know,boost::functionin real life is a template, so the compiler knows (14.2/3):Now we are back to the same problem as with
typename. What if we can't know yet whether the name is a template when parsing the code? We will need to inserttemplateimmediately before the template name, as specified by14.2/4. This looks like:Template names can not only occur after a
::but also after a->or.in a class member access. You need to insert the keyword there too:Dependencies
For the people that have thick Standardese books on their shelf and that want to know what exactly I was talking about, I'll talk a bit about how this is specified in the Standard.
In template declarations some constructs have different meanings depending on what template arguments you use to instantiate the template: Expressions may have different types or values, variables may have different types or function calls might end up calling different functions. Such constructs are generally said to depend on template parameters.
The Standard defines precisely the rules by whether a construct is dependent or not. It separates them into logically different groups: One catches types, another catches expressions. Expressions may depend by their value and/or their type. So we have, with typical examples appended:
T)N)(T)0)Most of the rules are intuitive and are built up recursively: For example, a type constructed as
T[N]is a dependent type ifNis a value-dependent expression orTis a dependent type. The details of this can be read in section(14.6.2/1) for dependent types,(14.6.2.2)for type-dependent expressions and(14.6.2.3)for value-dependent expressions.Dependent names
The Standard is a bit unclear about what exactly is a dependent name. On a simple read (you know, the principle of least surprise), all it defines as a dependent name is the special case for function names below. But since clearly
T::xalso needs to be looked up in the instantiation context, it also needs to be a dependent name (fortunately, as of mid C++14 the committee has started to look into how to fix this confusing definition).To avoid this problem, I have resorted to a simple interpretation of the Standard text. Of all the constructs that denote dependent types or expressions, a subset of them represent names. Those names are therefore "dependent names". A name can take different forms - the Standard says:
An identifier is just a plain sequence of characters / digits, while the next two are the
operator +andoperator typeform. The last form istemplate-name <argument list>. All these are names, and by conventional use in the Standard, a name can also include qualifiers that say what namespace or class a name should be looked up in.A value dependent expression
1 + Nis not a name, butNis. The subset of all dependent constructs that are names is called dependent name. Function names, however, may have different meaning in different instantiations of a template, but unfortunately are not caught by this general rule.Dependent function names
Not primarily a concern of this article, but still worth mentioning: Function names are an exception that are handled separately. An identifier function name is dependent not by itself, but by the type dependent argument expressions used in a call. In the example
f((T)0),fis a dependent name. In the Standard, this is specified at(14.6.2/1).Additional notes and examples
In enough cases we need both of
typenameandtemplate. Your code should look like the followingThe keyword
templatedoesn't always have to appear in the last part of a name. It can appear in the middle before a class name that's used as a scope, like in the following exampleIn some cases, the keywords are forbidden, as detailed below
On the name of a dependent base class you are not allowed to write
typename. It's assumed that the name given is a class type name. This is true for both names in the base-class list and the constructor initializer list:In using-declarations it's not possible to use
templateafter the last::, and the C++ committee said not to work on a solution.