AIX 模板使用
Using C++ templates
In C++, you can use a template to declare a set of related:
- Classes (including structures)
- Functions
- Static data members of template classes
Within an application, you can instantiate the same template multiple times with the same arguments or with different arguments. If you use the same arguments, the repeated instantiations are redundant. These redundant instantiations increase compilation time, increase the size of the executable, and deliver no benefit.
There are four basic approaches to the problem of redundant instantiations:
- Code for unique instantiations
- Organize your source code so that the object files contain only one instance of each required instantiation and no unused instantiations. This is the least usable approach, because you must know where each template is defined and where each template instantiation is required.
- Instantiate at every occurrence
- Use the -qnotempinc and -qnotemplateregistry compiler options (these are the default settings). The compiler generates code for every instantiation that it encounters. With this approach, you accept the disadvantages of redundant instantiations.
- Have the compiler store instantiations in a template include directory
- Use the -qtempinc compiler option. If the template definition and implementation files have the required structure, each template instantiation is stored in a template include directory. If the compiler is asked to instantiate the same template again with the same arguments, it uses the stored version instead. This approach is described in Using the -qtempinc compiler option.
- Have the compiler store instantiation information in a registry
- Use the -qtemplateregistry compiler option. Information about each template instantiation is stored in a template registry. If the compiler is asked to instantiate the same template again with the same arguments, it points to the instantiation in the first object file instead. The -qtemplateregistrycompiler option provides the benefits of the -qtempinc compiler option but does not require a specific structure for the template definition and implementation files. This approach is described in Using the -qtemplateregistry compiler option.
The -qtempinc and -qtemplateregistry compiler options are mutually exclusive.
Using the -qtemplateregistry compiler option
Unlike -qtempinc, the -qtemplateregistry compiler option does not impose specific requirements on the organization of your source code. Any program that compiles successfully with -qnotempinc will compile with -qtemplateregistry.
The template registry uses a "first-come first-served" algorithm:
- When a program references a new instantiation for the first time, it is instantiated in the compilation unit in which it occurs.
- When another compilation unit references the same instantiation, it is not instantiated. Thus, only one copy is generated for the entire program.
The instantiation information is stored in a template registry file. You must use the same template registry file for the entire program. Two programs cannot share a template registry file.
The default file name for the template registry file is templateregistry, but you can specify any other valid file name to override this default. When cleaning your program build environment before starting a fresh or scratch build, you must delete the registry file along with the old object files.
Recompiling related compilation units
If two compilation units, A and B, reference the same instantiation, the -qtemplateregistry compiler option has the following effect:
- If you compile A first, the object file for A contains the code for the instantiation.
- When you later compile B, the object file for B does not contain the code for the instantiation because object A already does.
- If you later change A so that it no longer references this instantiation, the reference in object B would produce an unresolved symbol error. When you recompile A, the compiler detects this problem and handles it as follows:
- If the -qtemplaterecompile compiler option is in effect, the compiler automatically recompiles B during the link step, using the same compiler options that were specified for A. (Note, however, that if you use separate compilation and linkage steps, you need to include the compilation options in the link step to ensure the correct compilation of B.)
- If the -qnotemplaterecompile compiler option is in effect, the compiler issues a warning and you must manually recompile B.
Switching from -qtempinc to -qtemplateregistry
Because the -qtemplateregistry compiler option does not impose any restrictions on the file structure of your application, it has less administrative overhead than -qtempinc. You can make the switch as follows:
- If your application compiles successfully with both -qtempinc and -qnotempinc, you do not need to make any changes.
- If your application compiles successfully with -qtempinc but not with -qnotempinc, you must change it so that it will compile successfully with -qnotempinc. In each template definition file, conditionally include the corresponding template implementation file if the __TEMPINC__ macro is not defined. This is illustrated in Example of -qtempinc.
Using the -qtempinc compiler option
To use -qtempinc, you must structure your application as follows:
- Declare your class templates and function templates in template header files, with a .h extension.
- For each template declaration file, create a template implementation file. This file must have the same file name as the template declaration file and an extension of .c or .t, or the name must be specified in a #pragma implementation directive. For a class template, the implementation file defines the member functions and static data members. For a function template, the implementation file defines the function.
- In your source program, specify an #include directive for each template declaration file.
- Optionally, to ensure that your code is applicable for both -qtempinc and -qnotempinc compilations, in each template declaration file, conditionally include the corresponding template implementation file if the __TEMPINC__ macro is not defined. (This macro is automatically defined when you use the -qtempinc compilation option.)
This produces the following results:
- Whenever you compile with -qnotempinc, the template implementation file is included.
- Whenever you compile with -qtempinc, the compiler does not include the template implementation file. Instead, the compiler looks for a file with the same name as the template implementation file and extension .c the first time it needs a particular instantiation. If the compiler subsequently needs the same instantiation, it uses the copy stored in the template include directory.
Example of -qtempinc
This example includes the following source files:
- A template declaration file: stack.h.
- The corresponding template implementation file: stack.c.
- A function prototype: stackops.h (not a function template).
- The corresponding function implementation file: stackops.cpp.
- The main program source file: stackadd.cpp.
In this example:
- Both source files include the template declaration file stack.h.
- Both source files include the function prototype stackops.h.
- The template declaration file conditionally includes the template implementation file stack.c if the program is compiled with -qnotempinc.
Template declaration file: stack.h
This header file defines the class template for the class Stack.
#ifndef STACK_H #define STACK_H template <class Item, int size> class Stack { public: void push(Item item); // Push operator Item pop(); // Pop operator int isEmpty(){ return (top==0); // Returns true if empty, otherwise false } Stack() { top = 0; } // Constructor defined inline private: Item stack[size]; // The stack of items int top; // Index to top of stack }; #ifndef __USE_STL_TEMPINC__ // 3 #include "stack.c" // 3 #endif // 3 #endif
Template implementation file: stack.c
This file provides the implementation of the class template for the class Stack.
template <class Item, int size> void Stack<Item,size>::push(Item item) { if (top >= size) throw size; stack[top++] = item; } template <class Item, int size> Item Stack<Item,size>::pop() { if (top <= 0) throw size; Item item = stack[--top]; return(item); }
Function declaration file: stackops.h
This header file contains the prototype for the add function, which is used in both stackadd.cpp and stackops.cpp.
void add(Stack<int, 50>& s);
Function implementation file: stackops.cpp
This file provides the implementation of the add function, which is called from the main program.
#include "stack.h" // 1 #include "stackops.h" // 2 void add(Stack<int, 50>& s) { int tot = s.pop() + s.pop(); s.push(tot); return; }
Main program file: stackadd.cpp
This file creates a Stack object.
#include <iostream.h> #include "stack.h" // 1 #include "stackops.h" // 2 main() { Stack<int, 50> s; // create a stack of ints int left=10, right=20; int sum; s.push(left); // push 10 on the stack s.push(right); // push 20 on the stack add(s); // pop the 2 numbers off the stack // and push the sum onto the stack sum = s.pop(); // pop the sum off the stack cout << "The sum of: " << left << " and: " << right << " is: " << sum << endl; return(0); }
Regenerating the template instantiation file
The compiler builds a template instantiation file in the TEMPINC directory corresponding to each template implementation file. With each compilation, the compiler can add information to the file but it never removes information from the file.
As you develop your program, you might remove template function references or reorganize your program so that the template instantiation files become obsolete. You can periodically delete the TEMPINC destination and recompile your program.
Using -qtempinc with shared libraries
In a traditional application development environment, different applications can share both source files and compiled files. When you use templates, applications can share source files but cannot share compiled files.
If you use -qtempinc:
- Each application must have its own TEMPINC destination.
- You must compile all of the source files for the application, even if some of the files have already been compiled for another application.