首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在使用“外部模板”时,专门化模板的正确方法是什么?

在使用“外部模板”时,专门化模板的正确方法是什么?
EN

Stack Overflow用户
提问于 2011-03-19 02:25:11
回答 2查看 12.1K关注 0票数 27

我希望有人能指出在使用“外部模板类”和“模板类”使用gnu c++进行显式实例化时,在模板类中专门化方法的正确方法。我试着用一个最简单的例子来总结这个问题,这个例子模拟了我真正的问题。声明“外部模板”似乎意味着模板实例化,这会在专门化方法时导致错误。给定一个驱动程序:

main.cc

代码语言:javascript
复制
#include A_H
#include <iostream>

int main()
{
    A<int> ai;
    A<long> al;

    std::cout << "ai=" << ai.get() << " al=" << al.get() << std::endl;

    return 0;
}

和下面的A的实现

a.h

代码语言:javascript
复制
template<typename T>
struct A
{
    int get() const;
};

extern template class A<int>;
extern template class A<long>;

a.cc

代码语言:javascript
复制
#include "a.h"

template<typename T>
int A<T>::get() const
{
    return 0;
}

template<>
int A<long>::get() const
{
    return 1;
}

template class A<int>;
template class A<long>;

当使用g++ 4.1.2或4.4.4进行编译时,我收到以下错误

代码语言:javascript
复制
 % g++ -Wall -g -D'A_H="a.h"' a.cc main.cc          
a.cc:10: error: specialization of 'int A<T>::get() const [with T = long int]' after instantiation
 %

如果我注释掉a.h中的两个"extern template“行,那么两个编译器都会按照预期进行编译和工作。我假设在没有“外部模板”的情况下依赖于显式实例化的存在即使在C++0x中也是未指定的行为,否则,C++0x添加“外部模板”有什么意义呢?

如果我将A实现为:

a-hack.h

代码语言:javascript
复制
template<typename T>
struct A
{
    int get() const;
};

template<typename T>
int A<T>::get() const
{
    return 0;
}

template<>
inline
int A<long>::get() const
{
    return 1;
}

extern template class A<int>;
extern template class A<long>;

a-hack.cc

代码语言:javascript
复制
#include "a-hack.h"

template class A<int>;
template class A<long>;

并再次编译,这将按预期工作

代码语言:javascript
复制
% g++ -Wall -g -D'A_H="a-hack.h"' a-hack.cc main.cc
% ./a.out 
ai=0 al=1

然而,在我的真实示例中,这会导致使用g++ 4.1.2 (在使用g++ 4.4.4时)的程序崩溃。我还没有缩小崩溃的确切原因(分段故障)。它只是看起来好像堆栈指针在调用A<>::get()时已损坏。

我意识到显式模板实例化在这一点上是非标准的,但是有人会期望我上面所做的工作能起作用吗?如果不是,正确的方法是什么?

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-03-19 02:34:01

代码语言:javascript
复制
extern template class A<long>;

这一行说明A<long>将根据编译器已经看到的定义进行显式实例化。当您稍后添加专门化时,您就打破了这一含义。

将专门化的声明添加到头文件中。

代码语言:javascript
复制
template <typename T> struct A { /*...*/ };
template<> int A<long>::get() const;
extern template class A<int>;
extern template class A<long>;

一般而言,最好将尽可能多的专门化声明放在与主模板相同的头文件中,以减少编译器关于应将哪个声明用于任何特定实例化的意外。

请注意,如果您正在处理单个模板实体,则extern template声明不是必需的(与本例相反,在本例中,我们必须指示编译器有关类A<long>和函数A<long>::get())。如果你想在另一个翻译单元中专门化一个函数模板,只需编写template<>就足够了。

代码语言:javascript
复制
template<typename T> int freeGet() { return 0; }  // you can even add "inline" here safely!
template<> int freeGet<long>();  // this function is not inline (14.7.3/12)

但是你必须在那里有<>。如果省略了<>,声明将变成默认实现(return 0)的显式实例化,这可能不是您想要的!即使添加了extern,编译器也可以内联该默认实现;如果在传递-O2时代码意外中断,则可能意外地在某处遗漏了<>

票数 22
EN

Stack Overflow用户

发布于 2015-12-24 16:13:08

添加此答案以解决标题中的问题(模板实例化,而不一定是模板方法实例化)。

这非常类似于函数声明/定义。

header.

  • Explicit

  • 显式实例化声明:extern template class是一个声明,通常应该放在header.

  • Explicit实例化定义中:

是一个定义,一般应该放在cpp中。declaration.

  • Code后面的代码不会在对象文件中生成,在包含definition.

  • Without显式实例化的cpp的对象文件中生成,当实际使用模板时,将发生隐式实例化。这将在每个使用template.

  • Implicit实例化的编译单元(目标文件)中发生,如果遇到声明,则不会发生。这就是该机制的要点-避免由于编译器不信任只有一个编译单元负责实例化模板而导致的隐式实例化导致的目标代码重复。

更多信息here

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5356269

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档