考虑一个类模板
S
:
[
s.hpp
]
template <typename>
struct S
{
void f() { /* ... */ }
void g() { /* ... */ }
};
此类模板还附带一个包含
S<int>::g()
专业化的源文件:
[
s.cpp
]
template <>
void S<int>::g() { /* ... */ }
S
被多次实例化为 S<int>
。为了通过避免S<int>
的多次实例化来加快编译时间,我想在头文件extern template
中引入一个显式实例化声明(
s.hpp
),以及相应的显式实例化定义在源文件
s.cpp
:
[
s.hpp
](修改)
template <typename>
struct S
{
void f() { /* ... */ }
void g() { /* ... */ }
};
extern template struct S<int>;
[
s.cpp
](修改)
template <>
void S<int>::g() { /* ... */ }
template struct S<int>;
然而,这样做会导致以下编译错误:
<source>:11:14: error: explicit specialization of 'g' after instantiation
void S<int>::g() { /* ... */ }
^
<source>:8:23: note: explicit instantiation first required here
extern template class S<int>;
^
我认为错误发生是因为
extern template
仍然被认为是一个实例化,甚至认为它只是一个声明。
如何通过在面向客户的头文件中为
extern template
提供 S
声明来实现可能的编译加速,同时仍然在源文件中保留 S<int>::g
的显式专业化?
在头文件中,用
idndef
指令包裹extern显式实例化声明,这样你就可以在提供显式实例化定义的翻译单元中抑制它。
s.hpp
:
/* definition of S unchanged */
#ifndef S_DO_NOT_INSTANTIATE
extern template struct S<int>;
#endif
s.cpp
:
#define S_DO_NOT_INSTANTIATE
#include "s.hpp"
/* remainder unchanged */
也在标头中声明显式特化。
template <typename>
struct S
{
void f() { /* ... */ }
void g() { /* ... */ }
};
template <>
void S<int>::g();
extern template struct S<int>;
要提炼规则:显式特化的声明必须出现在实体是显式实例化(定义或声明)的主题之前。因为
S<int>
的显式实例化对S<int>::g
递归构成相同,所以需要提前声明特化
但让我们庆幸的是我们没有着火.