加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C 11 extern模板:我们在哪里真正需要它们?

发布时间:2020-12-16 06:52:43 所属栏目:百科 来源:网络整理
导读:在C03中,我们具有模板显式实例化定义(模板类Foo int),其强制模板类的实例化. 在C 11中,我们有模板显式实例化声明(extern模板类Foo int),它应该阻止模板类的隐式实例化. (Class template instantiation) 我试图模拟我实际需要显式实例化声明的情况,以减少编译
在C03中,我们具有模板显式实例化定义(模板类Foo< int>),其强制模板类的实例化.

在C 11中,我们有模板显式实例化声明(extern模板类Foo< int>),它应该阻止模板类的隐式实例化. (Class template instantiation)

我试图模拟我实际需要显式实例化声明的情况,以减少编译时间.但我不能.看起来一切都没有这个功能(或不能使用它).

这是一个例子:

//Foo.h
#pragma once
template<class T>
class Foo
{
    T inst;
public:
    Foo(T i);
    T& get() const;
};


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

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

template<class T>
T& Foo<T>::get() const { return inst; }

template class Foo<int>; //explicit instantiation definition


//test1.h
#pragma once
#include "Foo.h"

//This line does not work
//extern template class Foo<int>; //explicit instantiation declaration.

void baz();


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

void baz()
{
    Foo<int> foo(10);
    int i = foo.get();
}

结果不取决于我是否评论(extern模板类Foo< int&gt ;;)行. 这是* .obj文件的符号:

dumpbin /SYMBOLS test1.obj

011 00000000 UNDEF notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))’

012 00000000 UNDEF notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )

013 00000000 SECT4 notype () External | ?baz@@YAXXZ (void __cdecl baz(void))

dumpbin /SYMBOLS Foo.obj

017 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))

018 00000000 SECT6 notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )

注意在test1.obj中标记为UNDEF的Foo< int> :: Foo< int>(int)和int Foo< int> :: get(void)const这意味着它们必须在别处解析(即Foo仅被编译)一旦).

ATTEMP#2:

如果我在Foo.h文件中定义完整模板(没有显式实例化定义),那么extern模板没有帮助 – 模板编译两次(在test1.cpp和test2.cpp中).

例:

//test1.h
#pragma once
#include "Foo.h"
void baz();


//test1.cpp
#include "stdafx.h"
#include "test1.h"
void baz()
{
    Foo<int> foo(10); //implicit instantiation of Foo<int>
    int i = foo.get();
}


//test2.h
#pragma once
#include "Foo.h"
extern template class Foo<int>;
void bar();


//test2.cpp
#include "stdafx.h"
#include "test2.h"
void bar()
{
    Foo<int> foo(10); //should refer to Foo<int> from test1.obj but IT IS NOT
    int i = foo.get();
}

这是符号转储:

dumpbin /SYMBOLS test2.obj

01D 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))

01E 00000000 SECT8 notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )

01F 00000000 SECT6 notype () External | ?bar@@YAXXZ (void __cdecl bar(void))

dumpbin /SYMBOLS test1.obj

01D 00000000 SECT6 notype () External | ?baz@@YAXXZ (void __cdecl baz(void))

01E 00000000 SECT4 notype () External | ??0?$Foo@H@@QAE@H@Z (public: __thiscall Foo::Foo(int))

01F 00000000 SECT8 notype () External | ?get@?$Foo@H@@QBEHXZ (public: int __thiscall Foo::get(void)const )

在两个* .obj文件中,Foo呈现.

所以我的问题是显式实例化声明可能有用吗?或者我可能会在测试中遗漏一些东西?

我用的是VS2013编译器.

解决方法

这是一个很好的解释为什么ATTEMP#2不能按我的意愿工作:
Is there a bug with extern template in Visual C++?

简而言之,当您在头文件中定义和实现模板时,编译器可能会内联它.然后它通过标准(14.7.2 / 10“显式实例化”)使显式实例化定义不起作用.

所以我们需要强制编译器不内联模板.例如,在声明之后实现它.

template<class T>
class Foo {
   ...
   T get() const;
};

template<class T>
T Foo<T>::get() const
{ ... }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读