Research Collection

Student Paper

A profound reflection on C++ template mechanism

Author(s): Baumann, Rainer

Publication Date: 2003

Permanent Link: https://doi.org/10.3929/ethz-a-004770832

Rights / License: In Copyright - Non-Commercial Use Permitted

This page was generated automatically upon download from the ETH Zurich Research Collection. For more information please consult the Terms of use.

ETH Library

A profound reflection on C++ template mechanism

Rainer Baumann, ETH Zurich 2002/03 [email protected], http://hypert.net/education

Contents

A profound reflection on C++ template mechanism...... 1 Contents ...... 2 Preface ...... 3 1. Common aspects ...... 4 2. Template parameter and argument ...... 5 2.1 Type...... 5 2.2 Non-Type ...... 6 2.3 Template...... 8 3. Template specialization and overloading ...... 10 3.1 Explicit specialization ...... 10 3.2 Partial specialization of class template ...... 13 3.3 Overloading template function...... 16 4. Instantiation ...... 17 4.1 Implicit instantiation ...... 17 4.2 Explicit instantiation...... 17 5. Argument deducing and matching ...... 18 5.1 Referring to function templates...... 18 5.2 Matching of overloaded (template) functions ...... 21 5.3 Matching of class template partial specializations ...... 22 5.4 Compiler support...... 22 6. Statics in template...... 23 7. Member templates...... 24 7.1 Nested templates ...... 25 8. Friends ...... 26 8.1 Friend of template ...... 26 8.2 Template as friend...... 28 9. Names ...... 29 9.1 Typename ...... 29 9.2 Local declared names...... 29 9.3 Dependent names ...... 30 10. Ambiguities...... 31 10.1 Grammatical ambiguities ...... 31 10.2 Resolving ambiguities...... 32 11. Linkage, compilation and exporting templates...... 33 11.1 Inclusion model with duplicate elimination...... 33 11.2 Separate compilation model with trial linking ...... 34 11.3 Historical ...... 36 12. Compiler...... 37 12.1 GCC...... 37 12.2 VC6 ...... 37 12.3 .NET ...... 37 12.4 EDG...... 37 12.5 Borland ...... 38 12.6 Conclusion ...... 38 13. References...... 39 13.1 Official Documents ...... 39 13.2 Textbooks...... 39 13.3 Papers ...... 39 13.4 Archives, Discussion Groups, Guides...... 39 13.5 Tutorials...... 40 14. Examples...... 41

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 2/41 [email protected] Preface

This paper provides a profound reflection on C++ template mechanism and is not a tutorial. The reader should be familiar with the basic constructs of C++ template mechanism as well as with the fundamental principles of STL as containers and interators. This paper is ISO standard compliant and covers mostly all template topics in the standard.

This paper originates from a semester work at the Swiss Federal Institute of Technology Zurich ETH (www.ethz.ch), Department of Computer Science (www.inf.ethz.ch), Computer Systems Institute, Group Prof. Juerg Gutknecht, Ph.D. Eugene Zueff.

I’d like to thank my sponsor and tutor Ph.D. E. Zueff for his support. I’m grateful that he has given me the opportunity to write this work.

 Rainer Baumann, [email protected], 2002/03

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 3/41 [email protected] 1. Common aspects

Template mechanism is provided for functions and classes. Notice that there are three kinds of classes, ordinary classes, structs and unions. There exists no restriction for there use concerning templates. Remember that in structs and unions all members are public.

A class template shall not have the same name as anything else in the namespace. Function template names are not unique due to overloading.

Be warned, because of the complexity of templates for compiler writers the ISO standard often states that no diagnostics is required. That means that your compiler does not have to recognize some errors or analyse the reason of errors and that the program behaviour can be undefined.

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 4/41 [email protected] 2. Template parameter and argument

There are three different kinds of template parameters and arguments: type, non-type and template. All of them have their own special characteristics, which are discussed in the next paragraphs. First, let’s have a look at some general terms.

2.0.1 Specialties and technical details

A template parameter can be given a default value. That allows simplifying template instantiation. But there are some roles to take care on when using them. After a parameter with default value it is not allowed to declare any further parameters with no ones. So you always have to declare the non-default ones before. Default parameters may never be declared twice, for example in a header file and an implementation or in a specialization. template class X; // ok template class Y; // error: parameter with no default value // declared after one with default value template class X { … }; // error: default value declared twice

When a template is completely specified by default arguments, the argument list can also be empty but must be written out. Note that this is no argument deduction where the brackets cannot be omitted. template struct S { ... }; S<> s1; // ok S s2; // error

2.1 Type

Template type parameters are the most often used once. For example you can build a generic container taking advantage of them. template class Container { struct node { type val; node* next; }; node* root; public: void push(type val) { node temp; temp.next = root; root = *temp; temp.val=val; } type push() { type temp = &root.val; root = root.next;} }; Example t01.cc

The use of the STL container vector is demonstrated in Example t02.cc.

2.1.1 Specialties and technical details

Template type parameters are indicated with the keywords "class" or "typename" which can be used interchangeable.

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 5/41 [email protected] class A { }; struct B { }; union C { }; template class X { }; template class Y { }; main() { X x1; Y y1; X x2; Y y2; X x3; Y y3; X x4; Y y4; } Example t03.cc

The only nasty pitfall is to use a local unlinked or unnamed type as parameter. template class X { … }; void foo() { struct S { ... }; X x1; // error: local type with no linkage used as parameter X x2; // error: unnamed parameter }

If you overload a type template with another non-type one, any ambiguities are resolved by taking the type parameter. For Example template void f() { cout << “classI”; }; template void f() { cout << “int I”; }; main { f(); // prints class I }

2.1.2 Chosen applications

Here a nice function template converter using type parameters. It converts any printable type to a string and backwards. template T fromString(const std::string& s); template std::string toString(const T& t); Example t04.cc

Type parameters are often used in design patterns, e.g. in a factory as provided in Example t05.cc. A factory defines an for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

2.2 Non-Type

Non-type parameters can only be of the following types: pointer and references to objects and functions, enumerations, booleans, characters and integers. Especially you shall not use floating points or voids. Neither it is allowed to change or to assign to non-reference non-type parameters nor is it possible to take an address of such a parameter because they are statically compiled in.

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 6/41 [email protected] template struct S { type a [max]; }; main () { S s1; } Example t06.cc

2.2.1 Specialties and technical details

As with type parameters it is not allowed to use local unlinked or unnamed values as well as addresses of array elements and non-static class members. template class X { … }; struct S { int m; static int s; }; void foo() { X<”forbidden”> x3; // error: unnamed parameter X<&s.m> x4; // error: address to non-static member X<&S::s> x5; // ok }

2.2.2

Non-type parameters can be explicitly adjusted what sometimes change the outcome to something unintended. Here is a list of the most common conversions. Argument type Converted type numeric type matching numeric type array of T pointer to T function returning T pointer to function returning T pointer to class T pointer to base class of T reference to T never converted

2.2.3 Chosen applications

Non-type parameters are mostly used for class templates. Than in functions a non-type value can be passed as argument. But there are still some reasons why passing values to functions as template parameters. Using template parameter, some calculations can be done during compile time what speeds up the execution of a program. If a function is often called with same parameters the list of them can be shortened.

Here a nice random generator, which uses a non-type parameter in a template class. template class Urand { int used[upperBound]; bool recycle; public: Urand(bool recycle = false); int operator()(); // The "generator" function }; Example t07.cc

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 7/41 [email protected] 2.3 Template

A template template parameter is a template taking as parameter a class template. This technique is still very rarely used but very powerful. Ordinary templates provide an abstraction of implementation detail, local data and data types. Template template parameters give the possibility to introduce additional level of abstractions. The largest example is the C++ Standard Template Library (STL).

It is important to realize that a template template parameter is an uninstantiated template. template < typename T> class A; template < template < typename T> > class B; main() { B x1; // A is past as uninstanitated template B > x1; // A is not a template, it is already a complete defined type }

2.3.1 Chosen applications

Template template parameters can be very useful to give developers the facility to adapt the predefined behaviour of classes and functions according to their needs. For example you want to build an application where you log all calls to a as provided in the STL. The containers have to be interchangeable, so that also custom ones can be used. In consequence you have to use the corresponding iterator for each container. template < typename val_t, template class cont_t = std::vector> class log_cont { std:: alloc_t; // can also be passed as template parameter cont_t m_cont; //instantiate template template parameter public: typedef typename cont_t >::iterator iterator; iterator begin () { iterator i = m_cont.begin (); /* write to log */ return i; } // more delegated methods... }; main () { log_cont cont; // create list container cont.push_back("cool"); // push strings to vector } Example t08.cc

The first template parameter val_t is the type of the objects to be kept inside the store. Cont_t, the second one, is the template template parameter, which we are interested in. The declaration states that cont_t expects two template parameters T and A, therefore any standard conforming sequence container is applicable. We also provide a default value for the template template parameter, the standard container vector. When working with template template parameters, one has to get used to the fact that one provides a real class template as template argument, not an instantiation. The container's allocator alloc_t defaults to the standard allocator. Adding a further template parameter would allow to pass a non default container.

Template template parameters allow parameterising with incomplete types. That’s why they are often used for to achieve a high flexible in design. This is

Rainer Baumann, ETHZ 2002/03 A profound reflection on C++ template mechanism 8/41 [email protected] a of structural abstraction compared to the abstraction over simple types achieved with usual template parameters.

Lets try to apply a corresponding abstraction to generic functions as above to generic containers. In example t08.cc class users were given a convenient way to customize a complex according to their application contexts. Transferring this abstraction to generic functions, provides functions whose behavior is modifiable by their template template arguments. Let’s have a look at a generic printer for our container, which writes its content out in a customisable way: using namespace std; template