为什么“extern template”不能与shared_ptr一起使用?

6
我曾经有一个(看似)聪明的想法,即在stdafx.h中包含#include 后立即使用extern template class std::shared_ptr,以防止std::shared_ptr在数百个文件中被重复实例化,我认为我可以将template class std::shared_ptr放在单个.cpp文件中,以强制进行单个实例化,并希望节省编译/链接时间。然而,对生成的.cod和.obj文件的检查表明,shared_ptr代码仍然在所有地方创建。但是,如果我对自己的模板类使用完全相同的技术,则按预期工作。shared_ptr有什么特殊之处,不允许这种用法吗?也许是在本身中有些东西强制编译器在达到我的extern template语句之前创建一个实例(我非常确定stdafx.h中没有任何更高级别的东西使用shared_ptr)?
// 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>;

然后:

// 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>;

并且:

// 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());
}

拥有一些代码将有助于理解和诊断问题。 - R Sahu
不知道,问题本身似乎足够合理。虽然不知道答案。 - Lightness Races in Orbit
@RSahu 编辑了代码 - dlf
据我记得,你必须使用VS2013才能获得extern template支持,即使这样也不是很稳定。 - Mgetz
@Mgetz 我也是这样得出结论的,直到我发现它可以与我的模板类一起工作(只是不能与shared_ptr一起使用)。所以也许在2012年也有些问题... - dlf
1
@dlf请查看http://blogs.msdn.com/b/vcblog/archive/2013/06/28/c-11-14-stl-features-fixes-and-breaking-changes-in-vs-2013.aspx,据称根据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,它得到了支持。 - Mgetz
1个回答

7
标准文件中的 §14.7.2/10 规定如下:
除了内联函数和类模板特化,显式实例声明会抑制它们所引用的实体的隐式实例。
我在 VS2013 中检查了 std::shared_ptr<> 的实现,发现其具有内联构造函数。这很可能是你的 extern template 被忽略的原因。

1
我相信就是这样了。此外,我刚被引导到了 MS 文档中的这个注释:“专门化中的 extern 关键字仅适用于在类体外定义的成员函数。在类声明内部定义的函数被视为内联函数,并且总是会被实例化。” - dlf
实验证实了这一点。对于我在问题中提到的玩具模板类,如果我在类体外定义函数,则extern template有效。如果我在类体内定义它们,则无效。 - dlf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接