【问题标题】:Fold expression vs compile recursion折叠表达式与编译递归
【发布时间】:2019-04-16 09:46:09
【问题描述】:

c++17 中,我们有折叠表达式,它可以极大地简化可以使用编译器递归和 SFINAE 或重载来实现的代码。 比如下面的代码中

#include <iostream>
#include <utility>

template<typename ...Args>
void printer(Args&&... args) {
  (std::cout << ... << args) << '\n';
}

void printer_cpp11() { }

template <typename First, typename ...Args>
void printer_cpp11(First&& first, Args&&... args)
{
  std::cout << first;
  printer_cpp11(std::forward<Args>(args)...);
}

int main()
{
  printer(3, 4, "hello");

  std::cout << std::endl;

  printer_cpp11(3, 4, "hello");

  return 0;
}

c++17 函数 printer(取自 cpp reference)与它的 c++11 版本 printer_cpp11 的工作完全相同。

在编译时,会生成函数 printer_cpp11 的多个重载,而使用折叠表达式需要单个函数 printer

使用折叠表达式在性能方面是否比c++11 样式有优势?或者可以假设编译器内联printer_cpp11 的所有重载,从而创建具有同等性能的代码?

【问题讨论】:

  • printer(std::forward&lt;Args&gt;(args)...); 我想你的意思是printer_cpp11(std::forward&lt;Args&gt;(args)...);,对吧?
  • 我认为 printer_cpp11 应该自称,而不是 printer
  • 假设不能做,但你为什么不分析它。
  • @L.F.当然,修正错字
  • printer_cpp11 将导致编译器递归地实例化 sizeof…(Args) 不同的模板函数——这是模板膨胀和编译时间缓慢的常见情况

标签: c++ c++11 c++17 sfinae fold-expression


【解决方案1】:

由于内联,两个版本都会导致相同的代码生成,因此运行时性能完全相同:https://gcc.godbolt.org/z/VIHTvZ(代码已清除流杂乱)。

但是,折叠表达式的编译时间和内存使用率预计比递归实例化要好得多,因此,折叠表达式通常是首选。更不用说它们还提供了更简洁、更易于推理的代码。

【讨论】:

    【解决方案2】:

    只是添加到@SergeyA 的答案中,您可以通过执行类似...

    template <typename ...Args>
    void printer_cpp11_norecursion( Args&&... args)
    {
      using do_ = int[];
      do_{0,
        (std::cout << args,0)...
      };
    }
    

    应该生成与其他两个版本 (https://gcc.godbolt.org/z/hyAyiz) 相同的结果,在 c++11 上编译时间可能会更好。

    【讨论】:

    • 谢谢,这是我第一次看到这种语法。您正在用 0 初始化一个 int 数组,丢弃对 cout 的调用结果,对吗?
    【解决方案3】:

    编译器将为每个具有不同参数的调用创建一个新的 printer 实例,并在函数中展开 operator 调用:

    https://godbolt.org/z/Zz9Ik9

    你也可以在这里看到发生了什么:https://cppinsights.io/

    但最终 - 测量将揭示它是否会带来性能提升。

    【讨论】:

      猜你喜欢
      • 2019-04-27
      • 2022-02-07
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-30
      • 2015-02-19
      • 2023-03-24
      相关资源
      最近更新 更多