6

I had the (seemingly) bright idea of using extern template class std::shared_ptr<SomeWidelyUsedClass> in stdafx.h immediately after #include <memory> in order to prevent std::shared_ptr<SomeWidelyUsedClass> from being redundantly instantiated in hundreds of files, figuring I could place template class std::shared_ptr<SomeWidelyUsedClass> in a single .cpp in order to force a single instantiation and hopefully save on compile/link time. However, examination of the resulting .cod and .obj files shows that shared_ptr<SomeWidelyUsedClass> code is being created everywhere anyway. But if I use this exact same technique with my own template class, it works as expected. Is there something special about shared_ptr that precludes this use? Perhaps something in <memory> itself that forces the compiler to create an instantiation before it reaches my extern template statement (I'm very certain there's nothing higher up in stdafx.h that makes use of shared_ptr)?

To clarify:

// stdafx.h; included in every cpp in the project
#include <memory>
#include "SomeWidelyUsedClass.h" // no shared_ptr in here

// I expect this to prevent instantiation of std::shared_ptr<SomeWidelyUsedClass>
// in all compilation units that include this, except the one below.
extern template class std::shared_ptr<SomeWidelyUsedClass>;

Then:

// ExplicitTemplateInstantiations.cpp
#include "stdafx.h"

// I expect this to cause std::shared_ptr<SomeWidelyUsedClass>
// to be instantiated in this compilation unit
template class std::shared_ptr<SomeWidelyUsedClass>;

And:

// SomeOtherFile.cpp
#include "stdafx.h"
#include "SomeWidelyUsedClass.h"

void foo()
{
   // I expect that SomeOtherFile.obj will not include an instantiation of
   // std::shared_ptr<SomeWidelyUsedClass> since it was declared extern in stdafx.h
   std::shared_ptr<SomeWidelyUsedClass>(new SomeWidelyUsedClass());
}
dlf
  • 9,045
  • 4
  • 32
  • 58
  • Having some code will be helpful in understanding and diagnosing the problem. – R Sahu May 01 '14 at 16:28
  • Dunno, question seems reasonable enough as it is. Don't know the answer, though. – Lightness Races in Orbit May 01 '14 at 16:29
  • @RSahu edited with code – dlf May 01 '14 at 17:20
  • As I recall you have to get VS2013 to get `extern template` support, and even then it's iffy – Mgetz May 01 '14 at 17:22
  • @Mgetz That's what I was about to conclude, until I saw that it worked with my own template class (just not shared_ptr). So maybe it's also iffy in 2012... – dlf May 01 '14 at 17:24
  • 1
    @dlf check http://blogs.msdn.com/b/vcblog/archive/2013/06/28/c-11-14-stl-features-fixes-and-breaking-changes-in-vs-2013.aspx allegedy according to http://blogs.msdn.com/b/vcblog/archive/2013/12/02/c-11-14-core-language-features-in-vs-2013-and-the-nov-2013-ctp.aspx it's supported – Mgetz May 01 '14 at 17:25

1 Answers1

7

The standard says in §14.7.2/10:

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.

I just checked in VS2013 and the implementation of std::shared_ptr<> there has an inline constructor. This is probably the reason why your extern template is ignored.

jblume
  • 390
  • 1
  • 6
  • 1
    I believe that's it. In addition, I was just directed to this note in the MS docs: "The extern keyword in the specialization only applies to member functions defined outside of the body of the class. Functions defined inside the class declaration are considered inline functions and are always instantiated." – dlf May 01 '14 at 17:35
  • Experiment confirms this. For the toy template class I referred to in the question, if I define the functions outside the class body, `extern template` works. If I define them within it, it doesn't. – dlf May 01 '14 at 18:15