A Bite of Template in C++ (2)

I encountered two issues when using C++ template. One is about why sometimes typename has to be prefixed to declarations, and another is how to access the types in the parameter list from outside of the template. This post has some ideas for those two questions, as well as some discussions about nested templates.

The Keyword typename in Declarations

Qualified names and dependent names

Qualified name refers to a name with explicitly specified scope prefixed, and the scope could be namespace, struct, class. For example, std::cout is a qualified name, printf is an unqualified name, and vector<int>::iterator is a qualified name.

Dependent name refers to a name dependent on a template parameter. For instance:

In the above template class, non_depedent_i, non_depedent_vi, and non_depedent_pvi are non-depedent names, while depedent_i, depedent_vi, and depedent_pvi are depedent names.

The motivation to require typename in some declarations

It is highly likely that there are operations on depedent names inside a template. The depedent names are in “quantum state” when compiler evaluates the declaration of the template, and they do not “collapse” until instantiation. Naturally, some errors are not able to detect during evaluating the declaration, like whether the type T has a member called x, so compiler has to check one more time upon instantiation. However, there could be ambiguities occuring during instantiation. In the following code, both class Value and class Type have a member x. The difference is that in Value x is a constant, while in Type x is a type. For the statement T::x * Pi inside the template function accessValue(), either a value x or a type x makes sense. The statement becomes a multiplication for class Value, and declares a variable for class Type. After analysis, we find the ambiguities actually happen when the depedent names are used as scope name, which followed by scope resolution operator ::.

Disambiguation for declarations involving depedent scopes

The solution is C++ standard requires a disambiguator, typename, before depedent scope, to explicitly claim the member would be regarded as type. Implicitly, the names after depedent scope without the disambiguator typename would be treated as value or variable whenever it is possible. Here comes more examples:

In addition to typename disambiguator in some declarations, the keyword template could appear as disambiguator in some declarations as well. It has the similar motivation and solutions. See the following code for elaboration:

Template Parameter List Exposure

Visibility of templete parameter list

The type passed to template could be a template class, then comes the question:
is there are way for the template to know what type is used in the template class?
Here is a fragment of code about what I am questioning:

The compiler would complain “no type named ‘T’ in ‘class Inner'". Is it because class is pravite by default that causes `T` invisible? Simply change `class` to `struct` makes no difference.

Look at the statement Outer< Inner<int> > obj;. Compiler instantiates the class Inner<int> first, then instantiates the class Outer< Inner<int> >, and eventually creates the object obj. During the first instantiation of Inner<int>, all Ts inside the Inner template are substituted with int. When it comes to the turn for Outer< Inner<int> > to instantiate, there is no more T left in the Inner<int>. Definitely, compiler cannot find any type or variable or member function called T inside Inner<int>.

Therefore, theoretically types in the template parameter list is not visible outside the template.

Make them visible

There are two possible ways to make template types as “visible”, using typedef specifer or type alias.

It is straightforward to using typedef to expose types passed from parameter list. For example:

Note that the typedef statements must be in the public section.

Type alias is introduced since C++11. It uses the keyword using. Here comes an example that is equivalent to the previous typedef example:

Shadow and nest

However, the two solutions mentioned above are not perfect. As they create the new alias for outside access, they use new names for types. Instantiation is like simple substitution, and will not analysis to distinguish alias from the origin. If you try to keep the same name, then the compiler would complain like “shadows template parm ‘class Vertex_t’”. Furthermore shadow is even forbidden in nested scopes as well. Like the following code would not get compiled due to errors caused by shadow:

Although from my perspective, the ban is to save some effort to design compiler, here is an example from the stackoverflow thread Accessing template parameters of the member templates to justify the necessity:

The code has be heavily modified to get compiled and elaborate the idea. According to their post, the authors assume the template of Inner can use T1, thus shadows the T1 in Outer, then res1 should become true, which seems weird to the authors.

By the way, I failed to use the object out_bool to instantiate Inner template. As following code shows, I used knowledge in the first part of this post, trying to make it explicit, but none of them work.

Finally, I would like to mention the part 2 of their stackoverflow post is saying: partial specialization is allowed for nested templates, and the specialization could be the situation that the outer template and the inner template share a same type or types.

For example, if the struct Inner in the previous example takes more than one parameters, then we can define a partial specialization like follows:

Future Work

As the “blood” of metaprogramming, template has too much points to cover in one or two posts. I am not sure what would be my next post. It depends on what problem I encounter in the practice, I think.

Credits