The C++ standard has some new rules for templates that make old code nonconforming, particularly code involving the use of the new keyword typename. The 5.0 compiler does not yet enforce these rules, but does recognize this keyword. Template code that worked under the 4.2 compiler probably continues to work, although the 4.2 version accepted some invalid template code. You should migrate your code to the new C++ rules as development schedules permit, since future compilers will enforce the new rules.
The C++ standard has new rules for determining whether an identifier is the name of a type. The following example illustrates the new rules:
typedef int S; class B { ... typedef int U; ... } template< class T > class C : public B { S s; // OK T t; // OK U x; // 1 No longer valid B::U y; // 2 No longer valid T::V z; // 3 No longer valid };
The new language rules state that no base class is searched automatically to resolve type names in a template, and that no name coming from a base class or template parameter class is a type name, unless it is declared to be so with the keyword typename.
The first invalid line (1) in the code example tries to inherit U from B as a type without the qualifying class name and without the keyword typename. The second invalid line (2) correctly modifies the type with the name of the base class, but the typename modifier is missing. The third invalid line (3) uses type V coming from the template parameter, but omits the keyword typename. The definition of s is valid because the type doesn't depend on a base class or member of a template parameter. Similarly, the definition of t is valid because it uses type T directly, a template parameter which must be a type.
The following code shows the correct implementation:
typedef int S; class B { ... typedef int U; ... } template< class T > class C : public B { S s; // OK T t; // OK typename B::U x; // OK typename B::U y; // OK typename T::V z; // OK };
A problem for migrating code is that typename was not previously a keyword. If existing code uses typename as an identifier, you must first change the name to something else.
For code that must work with old and new compilers, you can add statements that are similar to the following example to a project-wide header file.
#ifdef TYPENAME_NOT_RECOGNIZED #define typename #endif
The effect is to conditionally replace typename with nothing. When using older compilers (such as Sun C++ 4.2) that do not recognize typename, add -DTYPENAME_NOT_RECOGNIZED to the set of compiler options in your makefile.
In the ARM, and in the 4.2 compiler, there was no standard way to request an explicit instantiation of a template using the template definition. The C++ standard, and the 5.0 compiler in standard mode, provide a syntax for explicit instantiation using the template definition; the keyword template followed by a declaration of the type. For example, the last line in the following code forces the instantiation of class MyClass on type int, using the default template definition.
template<class T> class MyClass { ... }; template class MyClass<int>; // explicit instantiation
The syntax for explicit specializations has changed. To declare an explicit specialization, or to provide the full definition, you now prefix the declaration with template<>. (Notice the empty angle brackets.) For example:
// specialization of MyClass class MyClass<char>; // old-style declaration class MyClass<char> { ... }; // old-style definition template<> class MyClass<char>; // standard declaration template<> class MyClass<char> { ... }; // standard definition
The declaration forms mean that the programmer has somewhere provided a different definition (specialization) for the template for the provided arguments, and the compiler is not to use the default template definition for those arguments.
In standard mode, the 5.0 compiler accepts the old syntax as an anachronism. The 4.2 compiler accepts the new specialization syntax, but does not treat code using the new syntax correctly in every case. (The standard changed after the feature was put into the 4.2 compiler.) For maximum portability of template specialization code, you can add statements similar to the following to a project-wide header:
#ifdef OLD_SPECIALIZATION_SYNTAX #define Specialize #else #define Specialize template<> #endif
Then you would write, for example:
Specialize class MyClass<char>; // declaration
The Sun implementation of C++ templates uses a repository for template instances. The C++ 4.2 compiler stored the repository in a directory called Templates.DB. The Sun C++ 5.0 compiler, by default, uses directories called SunWS_cache and SunWS_config. SunWS_cache contains the working files and SunWS_config contains the configuration files, specifically, the template options file (SunWs_config/CC_tmpl_opt). (See the C++ Users' Guide.)
If you have makefiles that for some reason mention repository directories by name, you need to modify the makefiles. Furthermore, the internal structure of the repository has changed, so any makefiles that access the contents of Templates.DB no longer work.
In addition, standard C++ programs probably make heavier use of templates. Paying attention to the considerations of multiple programs or projects that share directories is very important. If possible, use the simplest organization. You must compile only files belonging to the same program or library in any one directory. The template repository then applies to exactly one program. If you compile a different program in the same directory, clear the repository by using CCadmin -clean. See C++ User's Guide for more information.
The danger in more than one program sharing the same repository is that different definitions for the same name might be required. This situation cannot be handled correctly when the repository is shared.
The C++ standard library contains many templates, and many new standard header names to access those templates. The Sun C++ standard library puts declarations in the template headers, and implementation of the templates in separate files. If one of your project file names matches the name of a new template header, it is possible to pick up the wrong implementation file, and cause numerous, bizarre errors. Suppose you have your own template called vector, putting the implementation in a file called vector.cc. Depending on file locations and command-line options, it is possible for the compiler to pick up your vector.cc when it needs the one from the standard library, or vice-versa. When the export keyword and exported templates are implemented in a future compiler version, the situation will be worse.
There are two recommendations for preventing current and future problems:
Do not use any of the standard header names as names of your template files. All of the standard library is in namespace std, so you won't get direct name conflicts with your own templates or classes. You can still get indirect conflicts from using declarations or directives, so it is preferable not to duplicate template names from the standard library. The standard headers involving templates are as follows:
algorithm bitset complex deque exception fstream functional iomanip ios iosfwd iostream istream iterator limits list locale map memory numeric ostream queue set sstream stack stdexcept streambuf string typeinfo utility valarray vector
Put template implementations in the header (.h) file, instead of in a separate file, to prevent implementation file name conflicts. See C++ Users' Guide for more information.