C++11 – Part 4: Template Tidbits

C++11 saw a bunch of changes to template handling that overall are fairly minor. The first two will I cover allow what seem fairly obvious things that I am sure most C++ programmers attempted when they were learning the language. The third is not really a language change in itself, but more of a method to help the compiler and linker do less work.

Right-angle Brackets
When specifying a template within a template, there is no longer a need to put a space between the “>“s. For example, a poor man’s matrix can now be specified as:

std::vector<std::vector<double>>

Not a big feature by any means, but a great improvement!

Template Aliases
There are limitations with typedef and templates. Specifically, typedef can only be used to define fully qualified types, so does not work in cases where you want to partially specialize a template. The standard example (as in, straight from the Standard) is if you want to provide your own allocator for a std::vector. Now you can define a type for that using:

template<class T>
  using Vec = std::vector<T, Alloc<T>>;
Vec<int> v;    // same as std::vector<int, Alloc<int>> v;

Note that ordinary type aliases can be declared using the using syntax instead of typedef, and in my opinion is a far nicer syntax.

Extern Templates
To understand this feature, you first need to have some idea about how C++ compilers deal with templates. Lets see if I can explain this correctly… Consider this code snippet:

Foo<int> f;
f.bar();

When the compiler reaches the first line, it does a implicit initialization of the constructor (and destructor) of Foo<int> (if it has not been done previously in this translation block). That is, it creates the code for the int version of Foo. Generating the code on usage makes sense with templates as we do not know what types will be used when we declare the class (hence the use of templates…). The second line accesses the bar() method of Foo<int> and so that function gets implicitly initialized.

A disadvantage of implicit initialization is that we would have to use every method to let the compiler catch issues when using a class with a particular type. Also, the initialize a bit here and there approach might be slower. To work around this we can do an explicit initialization of the class:

template class Foo<int>;

The disadvantage of this is that if you class has a method that is not usable for a particular type (e.g. due to a class method requiring an operator that is not implemented for the type), then an explicit initialization will try to initialize that method and fail. With implicit initialization, the methods are initialized as called and so the unusable method is never encountered by the compiler. This is all in C++03.

OK… more details about the compiler. What happens when we have two translation units that are compiled separately then linked together that both use the Foo<int>? At compile time, the compiler has no idea that both these files use the that class, so initializes it for both files as needed. Not only is this a waste of compiler time, but then the linker spots these two identical initializations and strips one out (ideally…), so it wastes linker time too. C++11 provides a way to deal with this. In one source file, Foo<int> gets explicitly initialized. Then in all remaining source files that link with this, template initialization can be suppressed using:

extern template class Foo<int>;

One potential use for this is creating a shared library. If you know the finite set of types your template class/function is going to be used for, you can provide a header with just the declarations and the required extern lines. In the library source, you provide the definitions and explicitly initialize them. That way, any users of your library will just have to include the header and they are done. The compiler will automatically not implicitly initialize anything.

Comments are closed.