kna*_*ten 5 c++ visual-c++ c++11 visual-studio-2012
鉴于此代码:
//header.h
template <class T>
class Foo
{
public:
Foo(T t) : t(t) {}
T t;
};
//source1.cpp:
#include "header.h"
extern template class Foo<int>;
int main()
{
Foo<int> f(42);
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这个程序不应该链接,因为class Foo<int>任何地方都不应该有定义(extern template应该防止这个).使用VC++ 11(Visual Studio 2012),无论如何编译和链接.在海湾合作委员会,它没有:
source1.cpp:(.text+0x15): undefined reference to `Foo<int>::Foo(int)'
Run Code Online (Sandbox Code Playgroud)
如果我链接到source2.cpp但是它可以工作(正如我所期望的那样):
#include "header.h"
template class Foo<int>;
Run Code Online (Sandbox Code Playgroud)
根据这篇博文,自VC10以来应该支持extern模板. http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
另外,有没有办法在Windows/Visual Studio上列出目标文件中的名称?在Linux上我会这样做:
$ nm source1.o
U _ZN3FooIiEC1Ei <- "U" means that this symbol is undefined.
0000000000000000 T main
Run Code Online (Sandbox Code Playgroud)
Mic*_*urr 15
C++ 11 14.7.2/10"显式实例化"说:
除了内联函数和类模板特化之外,显式实例化声明具有抑制它们引用的实体的隐式实例化的效果.
您的类模板中的构造函数Foo<T>是内联的.如果你像这样构造标题,VS2012将按你期望的方式工作:
//header.h
template <class T>
class Foo
{
public:
Foo(T t);
T t;
};
template <class T>
Foo<T>::Foo(T t) : t(t)
{
}
Run Code Online (Sandbox Code Playgroud)
这样构造函数就不是内联的.
我在上面引用的标准中的段落确实包括以下注释:
[注意:意图是当使用odr(3.2)时,仍然会隐式实例化作为显式实例化声明主题的内联函数,以便可以考虑使用内联体,但是不需要外联副本内联函数的内容将在翻译单元中生成. - 结束说明]
查看内联ctor时创建的汇编代码,将ctor的外联副本放在目标文件中(即使在编译优化项的示例时甚至不调用ctor),因此MSVC不会似乎遵循标准的意图.但是,注释不是规范性的,所以我认为MSVC的行为是符合的.
关于从使用MSVC构建的目标文件转储符号的问题,您可以使用该dumpbin实用程序:
使用非内联构造函数编译示例时:
dumpbin /symbols test.obj
...
008 00000000 UNDEF notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo<int>::Foo<int>(int))
^^^^^
...
Run Code Online (Sandbox Code Playgroud)
使用内联的ctor编译示例:
00A 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo<int>::Foo<int>(int))
^^^^^
Run Code Online (Sandbox Code Playgroud)