How to use extern template

Nicol Bolas picture Nicol Bolas · Jul 29, 2011 · Viewed 11.3k times · Source

I've been looking through the N3291 working draft of C++0x. And I was curious about extern template. Section 14.7.3 states:

Except for inline functions and class template specializations, explicit instantiation declarations have the effect of suppressing the implicit instantiation of the entity to which they refer.

FYI: the term "explicit instantiation declaration" is standard-speak for extern template. That was defined back in section 14.7.2.

This sounds like it's saying that if you use extern template std::vector<int>, then doing any of the things that would normally implicitly instantiate std::vector<int> will not do so.

The next paragraph is more interesting:

If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation (14.7.1) in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.

FYI: the term "explicit instantiation definition" is standard speak for these things: template std::vector<int>. That is, without the extern.

To me, these two things say that extern template prevents implicit instantiation, but it does not prevent explicit instantiation. So if you do this:

extern template std::vector<int>;
template std::vector<int>;

The second line effectively negates the first by explicitly doing what the first line prevented from happening implicitly.

The problem is this: Visual Studio 2008 doesn't seem to agree. The way I want to use extern template is to prevent users from implicitly instantiating certain commonly-used templates, so that I can explicitly instantiate them in the .cpp files to cut down on compile time. The templates would only be instantiated once.

The problem is that I have to basically #ifdef around them in VS2008. Because if a single translation unit sees the extern and non-extern version, it will make the extern version win and nobody would ever instantiate it. And then come the linker errors.

So, my questions are:

  1. What is the correct behavior according to C++0x? Should extern template prevent explicit instantiation or not?
  2. If the answer to the previous question is that it should not, then VS2008 is in error (granted, it was written well before the spec, so it's not like it's their fault). How does VS2010 handle this? Does it implement the correct extern template behavior?

Answer

Johannes Schaub - litb picture Johannes Schaub - litb · Jul 29, 2011

It says

Except for ...class template specializations

So it does not apply to std::vector<int>, but to its members (members that aren't inline member functions and presumably that aren't nested classes. Unfortunately, there isn't a one term that catches both of "class template specialization and specializations of member classes of class templates". So there are some places that use only the former but mean to also include the latter). So std::vector<int> and its nested classes (like std::vector<int>::iterator, if it is defined as a nested class) will still be implicitly instantiated if needed.