Using HP aC++ Templates

The following sections overview template processing and describe the instantiation coding methods available to you.

Invoking Compile-time Instantiation

Scope and Precedence

Explicit instantiation provides instantiation for a particular template class or template function. While command line options and the default compile-time instantiation provide instantiation at the level of the translation unit.

If you use explicit instantiation in addition to command-line options or default instantiation, explicit instantiation takes precedence.

For example, using the +inst_compiletime option requests instantiation of all used template functions and all static data members and member functions of instantiated template classes within a translation unit. Whereas, using explicit instantiation requests instantiation of all members of a particular template class or a particular template function.

Migration Considerations

See Also:


Why Use Compile-Time Instantiation

Note : If you used automatic instantiation with earlier versions of HP aC++ be aware of some possible migration problems and solutions.

Template Processing

The new HP aC++, compile-time instantiation as the default template instantiation mechanism. Following is the overview of template processing. For more detailed information, refer to the technical document Using Templates in HP aC++.

During compile-time instantiation, the compiler instantiates every template entity it sees in a translation unit provided it has the required template definition.

Compile-time Template Processing

For More Information


Migrating from the Automatic Instantiation Default to the Compile-time Instantiation Default

If you used automatic instantiation with earlier versions of HP aC++ there will be some known migration problems. The following migration problems may occur:

The following sections describe specific migration scenarios and illustrate possible migration problems and solutions.

Possible Duplicate Symbols in Shared Libraries

An existing compiler defect may be more apparent, if in HP aC++ A.02.00 or A.01.04 and prior versions you built a shared library using automatic instantiation (the prior default using the assigner) and now build that library using the current default (compile-time) instantiation. The defect relates to template objects with constructors or other runtime initializers that have been globally defined in more than one shared library on the link line. If such an object is defined in n shared libraries, it will be initialized and destructed n times at runtime.

When building the same application with the current default, the libraries are not closed prior to the final link, and the likelihood of a template symbol being defined in more than one shared library will increase.

Possible Duplicate Symbols in Archive Libraries

If in HP aC++ A.02.00 or A.01.04 and prior versions you built an archive library using automatic instantiation (the prior default using the assigner) and you rebuild that library using the current default (compile-time) instantiation, it is possible that duplicate symbol problems not apparent in the prior release will generate errors in the current release.

This is because the current default uses the linker rather than the assigner to determine which object file to pick to satisfy instantiation requests. For example, when your archive library is linked with an application, library objects in the link may be different than those used when linking the library in a prior release.

Following are two examples of building an archive library, one built with +inst_auto/+inst_close (the prior default), the other built with the current (compile-time) default.

Building an Archive Library with +inst_auto/+inst_close

Suppose for lib.inst_auto.a, the linker chooses foo2.o to resolve symbol x, and foo3.o to resolve symbol stack <int>. Symbols x, y, and stack <int> are each resolved with no duplicates. lib.inst_auto.a ------------------------------------------------- | foo.o | foo2.o | foo3.o | | | | stack<int> | | x | x | y | | y | | | -------------------------------------------------

Building an Archive Library with the Default (Compile-time Instantiation)

Suppose for lib.default.a, the linker chooses foo2.o to resolve symbol x, and foo.o to resolve symbol stack <int>. Symbols x, y, and stack <int> are each resolved, but now there's a duplicate definition of symbol x. This will cause a linker duplicate symbol error. This is really a user error, but was not visible before.

NOTE:This example is not meant to account for all cases of changed behavior.

lib.default.a ------------------------------------------------- | foo.o | foo2.o | foo3.o | | stack<int> | stack<int> | stack<int> | | x | x | y | | y | | | -------------------------------------------------


Explicit Instantiation

You request explicit instantiation by using the explicit template instantiation syntax (as defined in the ANSI/ISO C++ International Standard) in your source file.

You can request explicit instantiation of a particular template class or a particular template function. In addition, member functions and static data members of class templates may be explicitly instantiated.

Explicit instantiation of a class instantiates all member functions and static data members of that class, regardless of whether or not they are used. For example, following is a request to explicitly instantiate the Table template class with char*:

template class Table<char*>;

When you specify an explicit instantiation, you are asking the compiler to instantiate a template at the point of the explicit instantiation in the translation unit in which it occurs.

Usage

This might, for example, be useful when you are building a library for distribution and want to create a set of compiler-generated template specializations that you know will most commonly be used. Then when an application is linked with this library, any of these commonly used specializations need not be instantiated.

Another scenario might be a frequently used library that contains a repository of template specializations for your development team. Instantiating all such specializations in one, known translation unit would allow easy maintenance when changes are needed and eliminate cases of duplicate definition.

Performance

Although time is required to analyze and design code for explicit instantiation, compilation may be faster than for the equivalent implicit instantiation.

Examples of Explicit and Implicit Instantiation

Class Template

Following are examples of explicit and implicit instantiation syntax for a class template: template <class T> class Array; // forward declaration for the // Array class template template <class T> class Array {/*...*/}; // definition of the // Array class template template class Array <int>; // request to explicitly // instantiate Array<int> // template class Array <char> tc; // use of Array<char> // template class which // results in implicit // instantiation

Function Template

Following are examples of explicit and implicit instantiation syntax for a function template: template <class T> void sort(Array<T> &); // declaration for the sort() // function template template <class T> void sort(Array<T> &v) {/* ... */}; // definition of the sort() // function template template void sort<char> (Array <char>&); // request to explicitly // instantiate the sort<char> () // template function //NOTE <char> is not required if the compiler can deduce this. void foo() { Array <int> ai; sort(ai); // use of the sort<int> () } // template function which // results in implicit instantiation

For More Information

All template options on an aCC command-line apply to every file on the command line.

If you specify more than one option on a command-line, only the last option takes effect.


Compile-time Instantiation, the Default

By default, compile-time instantiation is in effect. Instantiation is attempted for any use of a template in the translation unit where the instantiation is used. All used template functions, all static data members and member functions of instantiated template classes, and all explicit instantiations are instantiated in the resulting object file.

If there are duplicate instantiations at link-time, the linker arbitrarily selects an instantiation for inclusion in the a.out or shared library.

The following command-lines are equivalent; each compiles a.C using compile-time instantiation.

aCC -c +inst_compiletime a.C

aCC -c a.C

Scope

If your source code contains templates and you do not specify any template command-line options nor explicit instantiations, compile-time instantiation takes place for any use of a template. If you specify a template command-line option, the option takes precedence for all translation units on the command line. Any explicit instantiation takes precedence over either a command-line option or compile-time instantiation.

Usage

Compared with developer-directed instantiation, compile-time instantiation involves less coding time for the developer. However, the design of your application may require the use of some form of directed instantiation. Also see inst_directed.

Debugging Templates

The HP WDB Debugger support C++ templates.

For More Information


C++ Template Tutorial

You can create class templates and function templates. A template defines a group of classes or functions. A template can have one or more types as parameters. When you use a template, you provide the particular types or constant expressions as actual parameters thereby creating a particular object or function.

Class Templates

A class template defines a family of classes. To declare a class template, you use the keyword template followed by the template's formal parameters. Class templates can take parameters that are either types or expressions. You define a template class in terms of those parameters. For example, the following is a class template for a simple stack class. The template has two parameters, the type specifier T and the int parameter size. The keyword class in the < > brackets is required to declare any template type parameters. The first parameter T is used for the stack element type. The second parameter is used for the maximum size of the stack.

template<class T, int size>
class Stack
{
public:
     Stack(){top=-1;}
     void push(const T& item){thestack[++top]=item;}
     T& pop(){return thestack[top--];}
private:
     T thestack[size];
     int top;
};

Class template member functions and member data use the formal parameter type, T, and the formal parameter expression, size. When you declare an instance of the class Stack, you provide an actual type and a constant expression. The object created uses that type and value in place of T and size, respectively. For example, the following program uses the Stack class template to create a stack of 20 integers by providing the type int and the value 20 in the object declaration:

void main()
{       Stack<int,20> myintstack;
        int i;

        myintstack.push(5);
        myintstack.push(56);
        myintstack.push(980);
        myintstack.push(1234);
        i = myintstack.pop();
}

The compiler automatically substitutes the parameters you specified, in this case int and 20, in place of the template formal parameters. You can create other instances of this template using other built-in types as well as user-defined types.

Function Templates

A function template defines a family of functions. To declare a function template, use the keyword template to define the formal parameters, which are types, then define the function in terms of those types. For example, the following is a function template for a swap function. It simply swaps the values of its two arguments:

template<class T> void swap(T& val1, T& val2) { T temp=val1; val1=val2; val2=temp; }

The argument types to the function template swap are not specified. Instead, the formal parameter, T, is a placeholder for the types. To use the function template to create an actual function instance (a template function), you simply call the function defined by the template and provide actual parameters. A version of the function with those parameter types is created (instantiated).

For example, the following main program calls the function swap twice, passing int parameters in the first case and float parameters in the second case. The compiler uses the swap template to automatically create two versions, or instances, of swap, one that takes int parameters and one that takes float parameters.

void main()
{       int i=2, j=9;
        swap(i,j);

        float f=2.2, g=9.9;
        swap(f,g);
}

Other versions of swap can be created with other types to exchange the values of the given type.