c++ - Visual C++ 中的外部模板是否存在错误?

标签 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);
}

根据我的理解,这个程序不应该链接,因为不应该有 class Foo<int> 的定义。任何地方( extern template 应该阻止这种情况)。然而,对于 VC++ 11 (Visual Studio 2012),这确实可以编译和链接。在 GCC 中,它不会:

source1.cpp:(.text+0x15): undefined reference to `Foo<int>::Foo(int)'

但是,如果我链接到 source2.cpp,它就可以工作(正如我所期望的那样):

#include "header.h"
template class Foo<int>;

根据这篇博文,extern template应该从VC10开始就支持了。 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

最佳答案

C++11 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.

还有类模板中的构造函数Foo<T>是内联的。如果您像这样构造 header ,VS2012 将按照您期望的方式工作:

//header.h
template <class T>
class Foo
{
public:
  Foo(T t);
  T t;
};

template <class T>
Foo<T>::Foo(T t) : t(t) 
{
}

这样构造函数就不是内联的。

我上面引用的标准中的段落确实包含以下注释:

[ Note: The intent is that an inline function that is the subject of an explicit instantiation declaration will still be implicitly instantiated when odr-used (3.2) so that the body can be considered for inlining, but that no out-of-line copy of the inline function would be generated in the translation unit. — end note ]

查看内联 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))
             ^^^^^
...

使用内联构造函数编译示例:

00A 00000000 SECT4  notype ()    External     | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo<int>::Foo<int>(int))
             ^^^^^

关于c++ - Visual C++ 中的外部模板是否存在错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13613926/

相关文章:

在 Active Directory 上开发的 C++ api

c++ - long long 到 long double 的转换

c++ - 标准要求 std::unordered_map 将键值对放在内存中吗?

c++ - C++中如何存储类成员对象

c++ - wxpython文件打开对话框

c++ - 如果声明无效

c++ - Visual Studio 作为代码浏览器 : How to preserve the directory structure?

c++跨平台方式定义64位无符号整数

c++ - Visual Studio 中 C++ 中 chkstk.asm stackoverflow 异常的建议

c++ - 偏特化不使用它的任何模板参数