【问题标题】:Scalability of variadic templates可变参数模板的可扩展性
【发布时间】:2013-10-03 13:11:18
【问题描述】:

我正在使用 C++11 开发一个大型软件基础架构,该基础架构广泛使用可变参数模板。我的问题如下:这种方法的可扩展性是什么?首先,可变参数模板可以采用的参数数量是否有上限?其次,当使用许多参数时,代码膨胀是否是最先进的编译器的主要问题(并且,通过扩展,这些参数的许多组合会产生模板化方法的许多不同实现)?

【问题讨论】:

  • 理论上没有限制,但显然在实践中存在一些限制,由一些有限的资源(如 RAM)决定。如果你达到了这个限制很重要的地步,你可能会遇到更大的问题,所以我不会担心那个。
  • 您的第二个问题很难回答,因为它更多地取决于代码的其余部分,而不是模板参数的数量。如果您使用许多模板参数来计算东西的编译时间,则可能不会生成任何代码。否则,如果正在生成代码,则实例化的数量将是一个乘法因素。这与非可变模板没有什么不同。
  • C++11 标准的附录 B(实现数量)没有具体说明 variadic 模板,但它建议至少有 256 个函数参数和 1024 个模板参数。但是,当您的名称过长时,您可能会更早遇到问题。
  • 编译器使用的模板参数有一个默认限制。您可以在 clang 和 gcc 上通过-ftemplate-depth-<number> 进行配置。还有-fconstexpr-depth=<number>。我自己无法对这两个进行太多调整。

标签: c++ c++11 scalability variadic-templates


【解决方案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&lt;0, ...&gt; 有大约 18000 个模板参数。

我发现 g++ 处理得很好。考虑了很长时间,并且使用了相当多的内存,但我无法通过增加模板参数的数量来让它失败。一旦模板递归深度设置得足够(即 900),Clang 3.1 也可以毫无问题地处理这个问题。

此外,尽管损坏的符号名称确实变得很大,但我无法使用它们破坏 nmld。 (值得注意的是,Linux/Itanium 修改方案使用替换,因此相同类型的重复模板参数不会重复整个类型名称,而是标记为S0S1 等。)快速谷歌没有'似乎对 ELF 符号长度有任何限制,但也许其他人知道是否存在这样的限制。

总之,至少对于 Linux 上的 g++ 和 clang,模板参数的数量似乎没有任何实际限制

至于你问题的第二部分,关于代码膨胀,很难说,特别是一旦涉及编译器优化。使用可变参数模板进行递归很容易,但是编译器也很容易摆脱中间类型。我只能建议试试看。

【讨论】:

  • 我使用的模板参数的数量(在生成的代码中)取决于客户,因此没有限制。因此,我的回答建议使用 boost::mpl 来避免这种限制。
猜你喜欢
  • 2014-04-12
  • 2014-10-30
  • 1970-01-01
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多