我正在使用 C++11 开发一个大型软件基础架构,该基础架构广泛使用可变参数模板。我的问题如下:这种方法的可扩展性是什么?首先,可变参数模板可以采用的参数数量是否有上限?其次,当使用许多参数时,代码膨胀是否是最先进的编译器的主要问题(并且,通过扩展,这些参数的许多组合会产生模板化方法的许多不同实现)?
1 回答
我想我应该去看看我的特定编译器的模板参数数量是否有任何限制(Linux 上的 g++ 4.8.1)。我使用了以下测试用例:
template <int I>
struct this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life {};
template <int Depth, typename... T>
struct A
{
using e = this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life<Depth>;
A() {};
A<Depth - 1, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, T...> a;
};
template <typename... T>
struct A<0, T...>
{
};
int main()
{
A<899> a;
}
模板递归深度限制在 g++ 中默认为 900,因此您会看到 899 参数。可笑的长结构名称用于查看我是否可以生成任何对于链接器而言太大而无法处理的符号 - 稍后会详细介绍。
如果您看不到测试用例中发生了什么,基本上每个实例化A
都会创建一个成员变量,该变量会添加 20 个额外的模板参数。部分特化用于停止递归。到最后,A<0, ...>
有大约 18000 个模板参数。
我发现 g++ 处理得很好。考虑了很长时间,并且使用了相当多的内存,但我无法仅仅通过增加模板参数的数量来让它失败。一旦模板递归深度设置得足够(即 900),Clang 3.1 也可以毫无问题地处理这个问题。
此外,尽管损坏的符号名称确实变得很大,但我无法破坏nm
或ld
使用它们。(值得注意的是,Linux/Itanium 修改方案使用替换,因此相同类型的重复模板参数不会重复整个类型名称,而是被标记S0
,S1
等等。)快速谷歌似乎没有出现任何ELF 符号长度的限制,但也许其他人知道是否存在这样的限制。
总之,至少对于 Linux 上的 g++ 和 clang ,模板参数的数量似乎没有任何实际限制。
至于你问题的第二部分,关于代码膨胀,很难说,特别是一旦涉及编译器优化。使用可变参数模板进行递归很容易,但是编译器也很容易摆脱中间类型。我只能建议尝试一下。