为了减少自由使用模板的大型项目中的编译时间,我使用“extern模板”(explicit template instantiation)获得了很好的结果,以防止在许多不同的模板函数中定义编制单位。
然而,令人烦恼的是它不适用于类定义中定义的成员函数。
例如,我有以下模板类:
template <typename T>
struct Foo
{
static T doubleIt(T input)
{
return input * 2;
}
};
现在,我知道Foo最常用于数字类型,因此我将其添加到标题中:
extern template struct Foo<int>;
extern template struct Foo<float>;
extern template struct Foo<double>;
在cpp文件中,添加显式实例化:
template struct Foo<int>;
template struct Foo<float>;
template struct Foo<double>;
这不起作用,因为obj文件上的dumpbin.exe告诉我:
017 00000000 SECT4 notype () External | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))
如果我改变我的类定义来定义函数在之外类标题,那么它可以正常工作:
template <typename T>
struct Foo
{
static T doubleIt(T input);
};
template <typename T>
T Foo::doubleIt(T input)
{
return input * 2;
}
我们可以使用dumpbin进行验证:
017 00000000 UNDEF notype () External | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))
该解决方案的问题是在类定义之外移动所有函数定义需要大量输入,特别是当您获得更多模板参数时。
我尝试过使用declspec(__ noinline),但它仍然没有正确地执行函数(并且在可能的情况下阻止函数的内联是不合需要的。)
有一件事是单独列举每个函数,就像这样,但这当然更麻烦:
extern template int Foo<int>::doubleIt(int);
extern template float Foo<float>::doubleIt(float);
extern template double Foo<double>::doubleIt(double);
我想要的是一种将函数定义保留在类定义中的方法,同时仍然允许在可能的情况下内联函数,但是当它没有内联时,只在编译单元中创建它实例化(换句话说,与在类定义之外移动函数的行为完全相同)。
答案 0 :(得分:1)
你不能两种方式,为了内联编译器需要使用源代码的方法,因为该方法是内联定义的,编译器不打算将它编译成目标文件,如果它不是直接在该对象中使用(即使它在所有情况下都是内联的,它也不会作为单独的方法存在于对象中)。 编译器总是必须构建你的函数,如果它在头文件中定义,以某种方式迫使编译器在目标文件中存储该函数的副本,而不会提高性能。
答案 1 :(得分:-1)
正如已经指出的那样,你不能同时拥有extern
和内联,但是关于额外的输入部分,我做了类似的事情并尝试使用预处理器将其最小化。我不确定你是否觉得有用,但为了以防万一,我会给一个带有模板函数的模板类的例子。
档案Foo.h
:
template<typename T1>
struct Foo
{
void bar(T1 input)
{
// ...
}
template<typename T2>
void baz(T1 input1, T2 input2);
};
#include <Foo.inl>
档案Foo.cc
:
template<typename T1>
template<typename T2>
void Foo<T1>::baz(T1 input1, T2 input2)
{
// ...
}
#define __FOO_IMPL
#include <Foo.inl>
#undef __FOO_IMPL
档案Foo.inl
:
#ifdef __FOO_IMPL
#define __FOO_EXTERN
#else
#define __FOO_EXTERN extern
#endif
#define __FOO_BAZ_INST(T1, T2) \
__FOO_EXTERN template void Foo<T1>::baz<T2>(T1, T2);
#define __FOO_INST(T1) \
__FOO_EXTERN template struct Foo<T1>; \
__FOO_BAZ_INST(T1, int) \
__FOO_BAZ_INST(T1, float) \
__FOO_BAZ_INST(T1, double) \
__FOO_INST(int)
__FOO_INST(float)
__FOO_INST(double)
#undef __FOO_INST
#undef __FOO_BAZ_INST
#undef __FOO_EXTERN
所以它仍然是一些写作,但至少你不必小心保持同步到不同的模板声明集,并且你不必明确地经历每种可能的类型组合。在我的例子中,我有一个带有两个类型参数的类模板,以及一些带有额外类型参数的成员函数模板,每个模板都有12种可能的类型。 36行优于12 3 = 1728,尽管我希望预处理器以某种方式遍历每个参数的类型列表,但无法确定如何。
作为旁注,在我的情况下,我正在编译一个DLL,我需要编译所有模板,所以实际上模板实例化/声明看起来更像__FOO_EXTERN template __FOO_API ...
。