gpt4 book ai didi

C++11 外部模板 : where do we actually need them?

转载 作者:行者123 更新时间:2023-12-02 22:43:12 29 4
gpt4 key购买 nike

在 C++03 中,我们有模板显式实例化定义 ( template class Foo<int> ),它强制模板类的实例化。

在 C++11 中,我们有模板显式实例化声明 ( extern template class 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 template class Foo<int>; )行。

这是两个 *.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 )

注意什么Foo<int>::Foo<int>(int)int Foo<int>::get(void)const在 test1.obj 中标记为 UNDEF,这意味着它们必须在其他地方解析(即 Foo 仅编译一次)。

尝试#2:

如果我在 Foo.h 文件中定义完整模板(没有显式实例化定义),则 extern template没有帮助 - 模板编译两次(在 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 )

在 Foo 提供的两个 *.obj 文件中。

所以我的问题是显式实例化声明有什么用处?或者也许我在测试中遗漏了一些东西?

我使用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
{ ... }

关于C++11 外部模板 : where do we actually need them?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40281137/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com