【问题标题】:Why is it not good to use recursive inheritance for std::tuple implementations?为什么对 std::tuple 实现使用递归继承不好?
【发布时间】:2012-03-27 08:31:13
【问题描述】:

this的问题中,霍华德·欣南特说

一些 std::tuple 的实现使用递归继承。但好人没有。 ;-)

有人可以解释一下吗?

【问题讨论】:

  • 可能与参数转发效率低有关?
  • 如果有人能概括出那些好和一些之间的区别可能会有所帮助。
  • @Cheers:我认为内联可以解决这个问题——但话又说回来,我不得不承认我已经遇到了直接决定停止内联的编译器超过 3 或 4 个。

标签: c++ c++11 stdtuple


【解决方案1】:

A non-recursive implementation 具有更好的编译时性能。信不信由你,在像std::tuple 这样的大量使用的库设施中,它的实现方式会影响(无论好坏)客户端看到的编译时间。递归实现往往会产生与递归深度呈线性关系的编译时间(甚至可能更糟)。

这不仅仅影响元组本身的实例化。 std::get<I>(tuple) 例如,一个实现需要线性数量的编译时间,另一个实现需要恒定数量的编译时间。在处理元组的元组时,这种影响可能会迅速恶化(或不会恶化)。 IE。递归实现可能会导致 O(N^2) 编译时间,而非递归实现仍然是 O(1)。

首先,libc++ 实现按客户端指定的顺序排列对象,但使用编译器的空基类优化工具优化空组件的空间。

【讨论】:

  • 这个问题(和你的回答)促使我探索非递归元组的实现。我写了一篇关于它的帖子:mitchnull.blogspot.com/2012/06/…。如果您能抽出一点时间阅读并指出任何错误,我将不胜感激。谢谢
  • 我使用 Howards 实现来改进我的一个较小的程序。我还在测试中包含了index tricks,以改进 tuple_element 的编译时间和可执行文件大小。令我惊讶的是,事情并没有变得更好,反而变得更糟。我正在使用 gcc 4.8.2。最新的 gcc 是否优化了尾头模板递归?还是上述技巧仅适用于极端情况?是否有任何示例或成功案例可以证明优化的有效性?
【解决方案2】:

我不记得 Andrei Alexandrescu 的 GoingNative 2012 演讲确切,但他谈到了这一点,他提到的其中一个要点是内存布局。如果我有一个std::tuple<int, short, char, char>,它将在内存中以char, short, int 的形式存在,并且此布局将比以int, short, char 布局时多占用(在我的系统上)4 个字节。 R. Martinho Fernandes 提醒我,最好的 方法是以最小化填充的顺序在内存中排序它们,这既不是给定的顺序 也不是 反向顺序。 (Naïve 继承的顺序是相反的)。

如果我写std::tuple<int, char, short, char>,一个通过朴素继承工作的元组会将它们按char, short, int 的顺序放入内存中,使用 3 个字节的填充,当最优具有零字节的填充时。 (int, short, char, charchar, char, short, int)。

假设我是对的,它是关于填充的,那么 R. Martinho Fernandes said “[我的论点] 并不排除以最佳顺序在实际实现中使用递归继承。”,这就是为什么我指定 naïve 继承是不好的。

(内存中的顺序确实意味着get<0> 将给出不同的对象,并且 R. Martinho Fernandes 正确地指出该顺序应该对用户不可见。但是,这些是我从 GoingNative 事件中得到了提醒。)

视频位于http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic,幻灯片位于http://ecn.channel9.msdn.com/events/GoingNative12/GN12VariadicTemplatesAreFunadic.pdf

【讨论】:

  • 他在评论中还谈了什么?
  • 如果一个元组“深度嵌套”足以给编译器带来负担,您可能需要再次查看您的代码。我认为没有困难的错误消息就可以做到这一点。
  • 啊,不是递归继承不好,而是naive递归继承?我想知道@Howard 是否有别的想法,是否有另一点支持另一种技术。
  • @MooingDuck:如果你有如此深的嵌套元组,那么我想说你想要做的最后一件事就是再次查看你的代码......;)跨度>
  • @MooingDuck 嘿,我写了一个非常粗略的元组实现,它总是为您提供最佳布局:ideone.com/Z5hfo。它计算最佳顺序(#ifdefed 用于 libc++ 和 libstdc++ 的实现),并从标准库中包装一个元组,以隐藏用户的真实顺序。我仍然无法在 GCC 上编译所有的 get<> 调用,但是所有的 static_asserts 都通过了,并且它在 libc++ 的 clang 上运行良好。我不知道如何进行编译时性能分析,所以这可能是低效的。如果您有任何问题,请在聊天中联系我 :)
【解决方案3】:

不使用基类链的一个原因是不涉及构造函数链:参数直接转发给适当的子对象。此外,似乎非递归实现对编译器的压力要小得多,并且创建的 [内部] 符号也少得多。更不用说实际上不是基类链更容易。

【讨论】:

    猜你喜欢
    • 2014-01-31
    • 1970-01-01
    • 2013-09-14
    • 2011-01-06
    • 2023-04-01
    • 2015-01-07
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多