The Oracle Solaris Studio 12.4 C++ 5.13 compiler enforces some C++ rules more strictly than past compilers. The incorrect rule enforcement caused earlier compilers to treat some valid code incorrectly. This section explains the stricter enforcement, provides examples of offending code, and shows how to fix the code. In all cases, you can change your code and it should still work with old and new compilers.
Previous compilers did not parse template definitions until the template was instantiated, with the following consequences:
Previous compilers would allow use of names not declared until after the template definition. Invalid code could be accepted, valid code could be rejected due to an apparent conflict, or the wrong declaration could be used.
Unconditional errors in templates that were not instantiated would not be diagnosed.
Names in a the definition of template T that do not depend on template parameters would not be instantiated until T was instantiated. They should be instantiated implicitly at the point where T is defined.
Example 1:
template< class T > int f(int i = j) // j is not visible { return i; } int j = 2; int main() { return f<int>(); }
Older compilers accepted this code because template f was not parsed until after j was defined.
Solution: Move the declaration of j ahead of the template.
Example 2:
#include <stdio.h> void f(double d) { printf("f(double)\n"); } template< class C > struct B { B() { f(1); } // f is not dependent on template parameter }; void f(int d) { printf("f(int)\n"); } int main() { B<int> b; // should print "f(double)" }
Solution: Be sure any declarations that the template should depend on occur before the template definition.
When looking up an unqualified name in a template definition, base classes that depend on a template parameter should not be examined. Previous compilers did incorrect name lookup.
Example:
template <typename T> struct Base { }; template <typename T> struct Derived : Base <T> { Derived() : Base() { } // unqualified Base should not be found }; Derived <int> x; template <typename T> struct Derived2 : Base <T> { Derived2() : Base<T>() { } // OK }; Derived2<int> x2; int main() { }
In class Derived, the use of unqualified Base without template arguments is not valid.
Solution: In class Derived2, the usage is correct.
You can no longer re-declare the name of a template parameter.
Example:
template <typename T> class A { typedef int T; }; // re-declare T
Solution: Pick a different name for the template parameter or for the local name.
The pre-1998 style of declaring an explicit specialization without template<> is no longer allowed.
Example:
template <typename T> class A { static T m; }; int A<int>::m = 0; // now an error
Solution:
template<> int A<int>::m = 0;
Refer to Template Definitions Separate. The "template definitions separate" compilation model is now more strict. When creating the X.cc file that has the definitions of templates declared in header X.h, you must be especially careful not to have anything else (that is, other than items directly associated with the definitions) in that file. You are now more likely to get "multiple definition" errors if you violate the rule.
Example:
% cat extdef.h template <typename T> T foo(T); % cat extdef.cc #include "extdef.h" int main() { foo(1); } % CC extdef.cc -template=extdef "extdef.cc", line 3: Error: main() already had a body defined. 1 Error(s) detected.
Solution: Remove everything from the X.cc file that is not needed for the template definitions. Recall that the X.cc file is not supposed to be explicitly compiled, because it is automatically included whenever the X.h file is included.
If extensive changes are needed, you might consider compiling with the -template=no%extdef option. That behavior is the default for other compilers, and is now the default in this release.
An implicit declaration of type int was never allowed in C++, but earlier compilers sometimes allowed it with a warning. Due to the way it interferes with proper template handling, the compiler no longer assumes you meant to declare something type int.
Example:
static i = 0; // now an error
Solution: Provide the type explicitly in the declaration.
When a friend declaration in class C for a function or class T was the first declaration of T, previous compilers incorrectly inserted the declaration of T into the surrounding scope. The Oracle Solaris Studio 12.4 C++ 5.13 compiler no longer does so, because it can lead to incorrect interpretation of valid programs.
Example:
class A { friend class B; // not previously declared friend void foo(); // not previously declared B* bar() // Error: B is not defined. { foo(); // Error: The function "foo" must have a prototype. return 0; } };
Solution: Declare the friend function or class in a scope outside the class before the class declaration that declares it a friend
class B; void foo(); class A { friend class B; // refers to prior declaration friend void foo(); // refers to prior declaration B* bar() // OK { foo(); // OK return 0; } };
When looking up names in a dependent function call, previous compilers incorrectly ignored static functions that were in scope. The Oracle Solaris Studio 12.4 C++ 5.13 compiler now treats static and extern functions the same way.
Example:
// previous compiliers ignored this bar() in dependent name lookup static int bar(int) { return 1; } int bar(long) { return 0; } template <typename T> int foo(T t) { // function call depends on template argument return bar(t); } int main() { return foo(0); }
Compiled with previous compilers, the program would return 0. With the Oracle Solaris Studio 12.4 C++ 5.13 compiler, the program returns 1.
When only a static function was found in name lookup, previous compilers would issue an error like
"Reference to static bar(int) not allowed in template foo(int), try using -features=tmplrefstatic."
See the previous example, with extern function bar(long) removed. The compiler now issues only a warning in -compat=5 mode because the code is technically an extension to the C++03 standard. In C++11 mode, the code is silently accepted because it is valid C++11.
The option -features=no%tmplrefstatic is still accepted, but has no net effect because references to static objects from templates are always allowed.