24

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?
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I think you have it covered here. The quotes from the standard say that it *should* work the way you want it to. However, both VS2008 and VS2010 were designed before that part entered the standard draft. They implement an MS extension that has been available for a long time, using then same keyword and similar behavior (but perhaps not identical). – Bo Persson Jul 29 '11 at 11:12
  • Not working correctly in VS2010, and [according to this](http://stackoverflow.com/questions/16797938/explicit-template-declaration-definition-in-vs-2012?rq=1) neither in VS2012. – Andreas Haferburg Aug 03 '13 at 11:33

1 Answers1

7

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.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    But `std::vector` is not a specialization; it is an instantiation of the template `std::vector`. – Nicol Bolas Jul 29 '11 at 19:27
  • @Nicol yes it's a specialization of `std::vector`. An instantiation is a generated specialization. You may want to read clause 14.7 – Johannes Schaub - litb Jul 29 '11 at 19:37
  • 3
    14.7.2, paragraph 5 states: "if an explicit instantiation of a template appears after a declaration of an explicit specialization for that template, the explicit instantiation has no effect." This seems to be talking about when a user would write a specialization (as opposed to a generated specialization). It's saying that an explicit instantiation definition for an explicit specialization is ignored, since there is an explicit specialization. – Nicol Bolas Jul 29 '11 at 20:17
  • @Nicol I misread paragraph 5. I read it as "if an explicit instantiation of a template appears after a declaration of an explicit instantiation for that template, the explicit instantiation has no effect.". I should read more closely next time. Fixed my answer, thanks for noting. – Johannes Schaub - litb Jul 29 '11 at 20:31