Rol*_*and 21 c++ templates c++11
我希望有人可以指出在模板类中专门化方法的正确方法,同时使用"extern模板类"和"模板类"进行gnu c ++的显式实例化.我试图通过模仿我真实问题的最简单的例子来解决这个问题.似乎声明"extern模板"意味着模板实例化,这在专门化方法时会导致错误.给出一个驱动程序:
main.cc
#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;
}
Run Code Online (Sandbox Code Playgroud)
以及A的以下实现
啊
template<typename T>
struct A
{
int get() const;
};
extern template class A<int>;
extern template class A<long>;
Run Code Online (Sandbox Code Playgroud)
a.cc
#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>;
Run Code Online (Sandbox Code Playgroud)
使用g ++ 4.1.2或4.4.4编译时收到以下错误
% 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
%
Run Code Online (Sandbox Code Playgroud)
如果我在ah中注释掉两个"extern模板"行,那么两个编译器都会按预期编译和工作.我假设在没有"extern模板"的情况下存在明确的实例化,即使在C++ 0x中也是未指定的行为,否则,C++ 0x添加"extern模板"的意义何在?
如果我改为将A实现为:
A-hack.h
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>;
Run Code Online (Sandbox Code Playgroud)
a-hack.cc
#include "a-hack.h"
template class A<int>;
template class A<long>;
Run Code Online (Sandbox Code Playgroud)
并再次编译,这按预期工作
% g++ -Wall -g -D'A_H="a-hack.h"' a-hack.cc main.cc
% ./a.out
ai=0 al=1
Run Code Online (Sandbox Code Playgroud)
但是,在我的真实示例中,这会导致程序崩溃,使用g ++ 4.1.2(在使用g ++ 4.4.4时).我没有缩小崩溃的确切原因(分段错误).它看起来好像堆栈指针在对A <> :: get()的调用中被破坏了.
我意识到显式模板实例化在这一点上是非标准的,但是有人会期望我上面所做的工作吗?如果没有,这样做的正确方法是什么?
谢谢
asc*_*ler 16
extern template class A<long>;
Run Code Online (Sandbox Code Playgroud)
这一行说明A<long>
要根据编译器已经看到的定义显式实例化.稍后添加专业化时,您会破坏其含义.
将您的专业化声明添加到头文件中.
template <typename T> struct A { /*...*/ };
template<> int A<long>::get() const;
extern template class A<int>;
extern template class A<long>;
Run Code Online (Sandbox Code Playgroud)
通常,最好在与主模板相同的头文件中放置尽可能多的特化声明,以减少编译器关于应该对任何特定实例使用哪个声明的意外.
请注意,extern template
如果您正在处理单个模板实体,则不需要声明(与此情况相反,我们必须向编译器指示类 A<long>
和函数 A<long>::get()
).如果你想在另一个翻译单元中专门化一个功能模板,那么只需编写即可template<>
.
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)
Run Code Online (Sandbox Code Playgroud)
但你必须拥有<>
那里.如果省略<>
,声明将变为默认实现(return 0
)的显式实例化,这可能不是您想要的!即使你添加extern
,也允许编译器内联该默认实现; 如果您的代码在通过时意外中断-O2
,您可能会意外地忽略了<>
某处.