The compiler warns when a class contains only private constructors or destructors, and has no friends. At the request of some of our customers, we have added a new option, `-Wctor-dtor-privacy' (on by default), and its negation, `-Wno-ctor-dtor-privacy', to control the emission of this warning. If, for example, you are working towards making your code compile warning-free, you can use `-Wall -Wno-ctor-dtor-privacy' to find the most common warnings.
There is now a mechanism which controls exactly when templates are expanded, so that you can reduce memory usage and program size and also instantiate them exactly once. You can control this mechanism with the option `-fexternal-templates' and its corresponding negation `-fno-external-templates'. Without this feature, space consumed by template instantiations can grow unacceptably in large-scale projects with many different source files. The default is `-fno-external-templates'.
You do not need to use the `-fexternal-templates' option when compiling a file that does not define and instantiate templates used in other files, even if those files are compiled with `-fexternal-templates'. The only side effect is an increase in object size for each file that was compiled without `-fexternal-templates'.
When your code is compiled with `-fexternal-templates', all template instantiations are external; this requires that the templates be under the control of `#pragma interface' and `#pragma implementation'. All instantiations that will be needed should be in the implementation file; you can do this with a typedef
that references the instantiation needed. Conversely, when you compile using the option `-fno-external-templates', all template instantiations are explicitly internal.
`-fexternal-templates' also allows you to finally separate class template function definitions from their declarations, thus speeding up compilation times for every file that includes the template declaration. Now you can have tens or even hundreds of lines in template declarations, and thousands or tens of thousands of lines in template definitions, with the definitions only going through the compiler once instead of once for each source file. It is important to note that you must remember to externally instantiate all templates that are used from template declarations in interface files. If you forget to do this, unresolved externals will occur.
In the example below, the object file generated (`example.o') will contain the global instantiation for `Stack<int>'. If other types of `Stack' are needed, they can be added to `example.cc' or placed in a new file, in the same spirit as `example.cc'.
foo.h
:
#pragma interface "foo.h" template<class T> class Stack { static int statc; static T statc2; Stack() { } virtual ~Stack() { } int bar(); };
example.cc
:
#pragma implementation "foo.h" #include "foo.h" typedef Stack<int> t; int Stack<int>::statc; int Stack<int>::statc2; int Stack<int>::bar() { }
Note that using `-fexternal-templates' does not reduce memory usage from completely different instantiations (`Stack<Name>' vs. `Stack<Net_Connection>'), but only collapses different occurrences of `Stack<Name>' so that only one `Stack<Name>' is generated.
`-falt-external-templates' selects a slight variation in the semantics described above (incidentally, you need not specify both options; `-falt-external-templates' implies `-fexternal-templates').
With `-fexternal-templates', the compiler emits a definition in the implementation file that includes the header definition, even if instantiation is triggered from a different implementation file (e.g. with a template that uses another template).
With `-falt-external-templates', the definition always goes in the implementation file that triggers instantiation.
For instance, with these two header files---
`a.h': #pragma interface template <class T> class A { ... }; `b.h': #pragma interface class B { ... }; void f (A<B>);
Under `-fexternal-templates', the definition of `A<B>' ends up in the implementation file that includes `a.h'. Under `-falt-external-templates', the same definition ends up in the implementation file that includes `b.h'.
You can control explicitly where a template is instantiated, without having to use the template to get an instantiation.
To instantiate a class template explicitly, write `template class name<paramvals>', where paramvals is a list of values for the template parameters. For example, you might write
template class A<int>
Similarly, to instantiate a function template explicitly, write `template fnsign' where fnsign is the particular function signature you need. For example, you might write
template void foo (int, int)
This syntax for explicit template instantiation agrees with recent extensions to the draft ansi standard.
The compiler's actions on ansi-related warnings and errors have been further enhanced. The `-pedantic-errors' option produces error messages in a number of new situations: using return
in a non-void
function (one returning a value); declaring a local variable that shadows a parameter (e.g., the function takes an argument `a', and has a local variable `a'); and use of the `asm' keyword. Finally, the compiler by default now issues a warning when converting from an int
to an enumerated type. This is likely to cause many new warnings in code that hadn't triggered them before. For example, when you compile this code,
enum boolean { false, true }; void f () { boolean x; x = 1; //assigning anint
to anenum
now triggers a warning }
you should see the warning ``anachronistic conversion from integer type to enumeral type `boolean'
''. Instead of assigning the value 1, assign the original enumerated value `true'.