Section 5.8. Template Instantiation Differences Between AIX and Linux

5.8. Template Instantiation Differences Between AIX and Linux

C++ templates are the first language feature to require more intelligence from the environment than one usually finds on a UNIX system. Somehow the compiler and linker have to make sure that each template instance occurs exactly once in the executable if it is needed, and not at all otherwise. The most popular method used by compilers today is to use a repository to store template instantiations and compile that code alone with all others as a final step in the compile process prior to linking. This is known as the CFront Model; you let the compiler handle managing and compiling the repository.

AIX handles this style with the qtempinc and qtemplateregistry parameters. The qtempinc parameter creates a tempinc directory in the present working directory, and the qtemplateregistry creates a templateregistry file in the present working directory. Both areas are used to hold template instantiation methods for the compiler to gather and compile prior to the link stage.

GNU handles this style with the frepo parameter. This parameter creates a file in the present working directory with an .rpo extension. It, too, holds template instantiation methods for the compiler to use as a final step prior to the link stage. It is the simplest and most recommended way to port template code from AIX to Linux. However, in addition to the parameter change, there are a few minor differences in the way you include template code in Linux rather than in AIX. The following subsections examine these differences and address some common concerns.

5.8.1. Using #pragma or #include

In AIX, the source that will be using the template code usually includes just the template header to get the full template implementation. Example 5-2 shows template instantiation under AIX.

Example 5-2. AIX Template

 stack.h  #ifndef STACK_H  #define STACK_H  #if __TEMPINC__  #pragma implementation ("stack.C")  #endif  template <class T> class stack  {  private:  T* v;  T* p;  int sz;  public:  stack(int s);  ~stack();  void push(T a);  T pop();  }; //..end of class Template Stack  #endif //..STACK_H main.cpp  #include <iostream>  using namespace std;  #include "stack.h"  int main()  {  stack<char> ch(10);  stack<int> integer(10);  ch.push('d');  ch.push('e');  integer.push(11);  integer.push(12);  cout << "char Stack pop 1 " << ch.pop() << endl;  cout << "char Stack pop 2 " << ch.pop() << endl;  cout << "char Stack pop 3 " << ch.pop() << endl;  cout << "Integer Stack pop 1 " << integer.pop() << endl;  cout << "Integer Stack pop 2 " << integer.pop() << endl;  cout << "Integer Stack pop 3 " << integer.pop() << endl;  } //..end of program 

In AIX, the template gets included here with an #include clause.

The #pragma implementation ("stack.C") clause located in the stack.h lets the compiler know where to find the implementation methods for the upcoming stack template class. In other words, it is a fancy include for the VisualAge C++ compiler. The AIX stack.C file follows:

stack.C #include "stack.h"  template <class T> stack<T>::stack(int s)  {  p = new T[sz=s];  v = p;  } //..end of stack::stack(..)  template <class T> stack<T>::~stack()  {  delete [] v;  } //..end of stack::~stack(..) destructor  template <class T> void stack<T>::push(T a )  {  *p++ = a;  } //..end of stack<T>::push(..)  template <class T> T stack<T>::pop()  {  T ret = *p;  p--;  return ret;  } //..end of stack<T>::pop(..) 

Example 5-3 shows how templates are instantiated under Linux. Note the difference in main.C and stack.C. In Linux, you must include the full template implementation code inside the main.C (whereas in AIX this work in done within the pragma clause inside the template .h file).

Example 5-3. Linux Template (AIX Example Modified)

main.C  #include <iostream>  using namespace std;  #include "stack.C" // Include the full implementation source here  int main()  { . . . Main body . . .  } //..end of program 

For Linux, in the stack.C the #pragma implementation identifier must be included as the first line at the top of the file that holds the implementation, as shown in the following syntax:

stack.C #pragma implementation "stack.h"  #include "stack.h"  template <class T> stack<T>::stack(int s)  {  p = new T[sz=s];  v = p;  } //..end of stack::stack(..)  …Remainder of code 

This tells the GNU compiler that this file is an implementation file and the interface to it is located in stack.h. Again, like AIX VisualAge C++, this is a fancy include statement for GNU.

Note the difference in syntax when using the pragma keyword between AIX and Linux. In addition, the GNU compiler does not require the header to be identified in the pragma statement. In such cases, the compiler uses the header filename of the file the pragma is being used in. It takes the filename, truncates the prefix (.C, .cpp, and so on), replaces it with an .h extension (stack.C = stack.h), and passes that name to the pragma statement. For instance, the preceding pragma identifier is rewritten here with a #pragma implementation clause:

stack.C #pragma implementation   // Knows to use stack.h  #include "stack.h"  template <class T> stack<T>::stack(int s)  {  p = new T[sz=s];  v = p;  } //..end of stack::stack(..)  …Remainder of code 

As you can see, with the exception of a few minor code changes, the frepo parameter in GNU is your best choice when porting AIX code that utilizes the qtempinc or qtemplateregistry. The nominal required code changes needed are where you must place the #pragma implementation identifier within the source. In AIX, this identifier is located in the header. For GNU, you must move this identifier to the top of the template implementation file.

5.8.2. Other Template Options Available Under GNU

If you do not want the burden of managing pragma flags on GNU version 3.2 and older, you can use the fno-implicit-templates parameter as an alternative to the frepo parameter. The fno-implicit-templates parameter gives you more control over what templates are instantiated and when. fno-implicit-templates

fno-implicit-templates disables the implicit generation of template instances, and explicitly instantiates all the ones you use. This approach requires more knowledge of exactly which instances you need, and allows greater control. You can scatter the explicit instantiations throughout your program, perhaps putting them in the translation units where the instances are used or the translation units that define the templates themselves. You can put all the explicit instantiations you need into one big file or create small files such as

#include "Foo.h" #include "" template class Foo<int>; template ostream& operator <<                 (ostream&, const Foo<int>&); 

for each of the instances you need, and create a template instantiation library from those.

As of GNU 3.2, however, the fno-implicit-templates is being deprecated. You should, therefore, only use the fno-implicit-templates flag as a short-term solution. Depending on the GNU compiler version you are using (prior to version 3.2), the GNU compiler can generate a warning if it no longer supports the option.

UNIX to Linux Porting. A Comprehensive Reference
UNIX to Linux Porting: A Comprehensive Reference
ISBN: 0131871099
EAN: 2147483647
Year: 2004
Pages: 175 © 2008-2017.
If you may any questions please contact us: