C++ “替代方案”;“外部模板”;在每个源文件中
我正在开发一个库,其中我们的许多核心对象都是模板,其中一个特定的实例化以指向该模板实例化的智能指针的形式显示在项目中的大多数文件中。我在单个源文件中显式实例化了这些模板。我们最近切换到C++11,我正在尝试使用新的C++ “替代方案”;“外部模板”;在每个源文件中,c++,templates,c++11,C++,Templates,C++11,我正在开发一个库,其中我们的许多核心对象都是模板,其中一个特定的实例化以指向该模板实例化的智能指针的形式显示在项目中的大多数文件中。我在单个源文件中显式实例化了这些模板。我们最近切换到C++11,我正在尝试使用新的 extern template class MyTemplate<double>; extern模板类MyTemplate; 加快编译速度。 我的第一个问题是我是否使用了智能指针 MyTemplate<double> MyTemplate 隐式实例化模
extern template class MyTemplate<double>;
extern模板类MyTemplate;
加快编译速度。
我的第一个问题是我是否使用了智能指针
MyTemplate<double>
MyTemplate
隐式实例化模板,并要求在文件顶部显示“extern template..”以避免重复实例化
我的第二个问题是,除了添加所有这些之外,是否还有其他选择
extern template class MyTemplate<double>;
extern模板类MyTemplate;
到每个源文件。对于我定义的每一个模板,它只需要对智能指针的每个实例进行一次有点繁琐的灰显,并确保在该文件中有正确的“extern template”行。我还可以看到,对于我们代码的未来开发人员来说,强制执行此约定有点困难,因为他们可能会添加模板实例化并忘记相应的外部模板行,特别是因为不会生成错误。如果您确定您将显式实例化模板,只需将显式实例化声明(extern模板的
行)放入头中,就可以将其包含在模板中
只要显式实例化定义(非extern
one)位于显式实例化声明(extern
one)之后,标准显式允许的实例化文件中出现这一行就没有问题。裁决在C++14.7.2/11中;C++11中也存在同样的规则。您可以将外部模板
声明直接放入定义模板
的头文件中。例如:
在文件有用的.hxx
中:
#ifndef USEFUL_HXX
#define USEFUL_HXX
namespace my
{
template <typename T>
T
do_useful_stuff(T x)
{
return x;
}
extern template int do_useful_stuff(int);
extern template float do_useful_stuff(float);
// Potentially many more...
} // namespace my
#endif // ifndef USEFUL_HXX
#include "useful.hxx"
namespace my
{
template int do_useful_stuff(int);
template float do_useful_stuff(float);
// Potentially many more...
} // namspace my
#include <iostream>
#include "useful.hxx"
int
main()
{
std::cout << my::do_useful_stuff(42) << std::endl;
std::cout << my::do_useful_stuff(1.0f) << std::endl;
}
最后在文件main.cxx
中:
#ifndef USEFUL_HXX
#define USEFUL_HXX
namespace my
{
template <typename T>
T
do_useful_stuff(T x)
{
return x;
}
extern template int do_useful_stuff(int);
extern template float do_useful_stuff(float);
// Potentially many more...
} // namespace my
#endif // ifndef USEFUL_HXX
#include "useful.hxx"
namespace my
{
template int do_useful_stuff(int);
template float do_useful_stuff(float);
// Potentially many more...
} // namspace my
#include <iostream>
#include "useful.hxx"
int
main()
{
std::cout << my::do_useful_stuff(42) << std::endl;
std::cout << my::do_useful_stuff(1.0f) << std::endl;
}
然后#将它包括在有用的.cxx中
#include "useful.hxx"
#define MY_EXTERN /* empty*/
#include "useful.txx"
#undef MY_EXTERN
和有用。hxx
#ifndef USEFUL_HXX
#define USEFUL_HXX
#ifndef MY_USE_EXTERN_TEMPLATES
#define MY_USE_EXTERN_TEMPLATES 0
#endif
namespace my
{
template <typename T>
T
do_useful_stuff(T x)
{
return x;
}
} // namespace my
#if MY_USE_EXTERN_TEMPLATES
#define MY_EXTERN extern
#include "useful.txx"
#undef MY_EXTERN
#endif
#endif // ifndef USEFUL_HXX
同样,我们可以编译有用的.cxx
和main.cxx
并将生成的对象文件链接在一起。如果我们不在main.cxx
中将MY_USE_EXTERN_TEMPLATES
定义为1,则可以一次性编译和链接该文件
我还可以看到,对于我们代码的未来开发人员来说,强制执行此约定有点困难,因为他们可能会添加一个模板实例化,而忘记相应的外部模板行,特别是因为不会生成错误
我不知道如何检测丢失的外部条目,但您可以使用静态断言,只允许对列出的类型实例化模板。这些将是您显式实例化的类型。下面是如何检查类模板的T
是否来自允许的类型列表()的示例:
//模板头
#包括
#包括
模板
结构是_any:std::false _type{};
模板
struct is_any:std::is_same{};
模板
结构是什么
:std::积分常数
{};
模板
类别MyT{
公众:
MyT();//不能是内联的,否则不会发生外部魔法
};
外部模板类MyT;
外部模板类MyT;
//Somwhere在应用程序代码中
int main()
{
//MyT dd1;//错误
MyT dd2;//确定
MyT dd3;//确定
}
//模板实现文件
模板
MyT::MyT(){
static_assert(是_any::value,“ups…你忘了做外部模板了!”);
}
模板类MyT;
模板类MyT;
为什么不将extern
声明放在头文件中?我考虑过这一点,但我发现的所有示例都将其放在源文件中。此外,如果我为每个模板类制作了一个头文件,其中包含所有“extern template class…”,并从每个源文件中包含该声明,我遇到了一个问题,我确实需要在一个文件中显式实例化,我相信“extern…”命令会推翻它。感谢您的详细回复。