使用extern模板时链接器错误

ted*_*ted 5 c++ linker templates c++11

我有一个模板工作代码.与stl :: string类似,我主要使用我的模板,在多个编译单元中有一个参数.为了节省时间,我试图使用extern实例化.但是,如下更改行会产生错误.做正确的方法是什么?(PS使用c ++ 0x标志编译gcc)

typedef myTemplate_base<commonType> myTemplate;
extern template class myTemplate_base<commonType>; //using "extern template myTemplate" wont work
Run Code Online (Sandbox Code Playgroud)

我在项目中添加了一个带有以下内容的额外cpp文件.

template class myTemplate_base<commonType>;
Run Code Online (Sandbox Code Playgroud)

链接器出现此错误消息(myTemplate someVar;将主文件中的第一个对象instantiation()行作为错误源):

未定义的引用'myTemplate_base :: ~myTemplate_base()'

但是,此类型在类中具有以下定义 ~myTemplate() = default;

编辑:如果你有一个更好的标题请评论,所以合适的人看看这个

编辑2:有趣的是,添加template class myTemplate_base<commonType>会极大地增加可执行文件的大小(在450k二进制文件上+ 100k),即使模板在main中使用(编译我必须注释掉extern部分).这暗示链接器保持模板的两个实现具有相同的实例/我忽略了某些东西.

def*_*ode 5

您找到了编译器错误.我转载它g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1.解决方法是将析构函数保留为隐式默认值.仅当析构函数显式标记为default(= default)时才会出现链接器错误.

无论哪种方式,析构函数永远不会使用extern模板生成.将模板类标记为extern,编译器会注意到任何需要的符号都是extern.除了析构函数之外,它仍然在文件中定义.看起来添加一个= defaultextern模板会让编译器误认为析构函数将在别处定义.

代码膨胀是由extern模板引起的.编译器仅实例化实际使用的模板类的方法.这通常远远小于定义的数量.当您使用force实例化一个类时extern template,编译器会为所有方法发出代码(您刚刚发现的析构函数除外).


g++ -c -std=c++0x main.cpp
g++ -c -std=c++0x extern.cpp
g++ main.o extern.o
Run Code Online (Sandbox Code Playgroud)

header.hpp

#pragma once

#include <iostream>
#include <string>
#include <typeinfo>

template< typename T >
class Foo
{
public:
   Foo( void ) :
      m_name( typeid(T).name() ),
      m_t( T() )
   { }

   // add or remove this to cause the error
   ~Foo( void ) = default;

   void printer( void )
   {
      std::cout << m_name << std::endl;
   }

   T returner( void )
   {
      return m_t;;
   }

private:
   std::string m_name;
   T m_t;
};

extern template class Foo<int>;
Run Code Online (Sandbox Code Playgroud)

extern.cpp

#include "header.hpp"

template class Foo<int>;
Run Code Online (Sandbox Code Playgroud)

main.cpp中

#include "header.hpp"

int main()
{
   Foo<int> fi;
   fi.printer();

   Foo<float> ff;
   ff.printer();
}
Run Code Online (Sandbox Code Playgroud)