简体   繁体   English

折叠表达式与编译递归

[英]Fold expression vs compile recursion

In c++17 we have fold expression which can greatly simplify code that could otherwise be implemented using compiler-recursion and SFINAE or overloading.c++17我们有折叠表达式,它可以大大简化可以使用编译器递归和 SFINAE 或重载实现的代码。 For example, in the following code例如,在下面的代码中

#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;
}

the c++17 function printer (taken from cpp reference ) does exactly the same job as its c++11 version printer_cpp11 . c++17函数printer (取自cpp 参考)与它的c++11版本printer_cpp11执行完全相同的工作。

At compile-time, several overloads of the function printer_cpp11 are generated, whereas a single function printer is needed using fold expression.在编译时,会生成函数printer_cpp11多个重载,而使用 fold 表达式需要单个函数printer

Is there an advantage in terms of performance in using fold expressions over the c++11 -style?c++11风格相比,使用折叠表达式在性能方面有优势吗? Or can one assume that the compiler inlines all the overloads of printer_cpp11 , creating code with equivalent performance?或者可以假设编译器内联了printer_cpp11所有重载,从而创建了具有等效性能的代码?

Both versions would lead to the same codegen due to inlining, so run-time performance is exactly the same: https://gcc.godbolt.org/z/VIHTvZ (code cleaned of streams clutter).由于内联,两个版本都会导致相同的代码生成,因此运行时性能完全相同: https : //gcc.godbolt.org/z/VIHTvZ (清除流混乱的代码)。

However, compilation times and memory usage are expected to be way better with fold expressions than with recursive instantiations, and because of that, fold expression are generally preferred.然而,折叠表达式的编译时间和内存使用预计比递归实例化要好得多,因此,折叠表达式通常是首选。 Not to mention they are also provide for cleaner and easier to reason about code.更不用说它们还提供了更清晰、更易于推理的代码。

Just to add to @SergeyA's answer you can alleviate the need for the recursion and the empty function in the c++11 version by doing something like...只是为了添加到@SergeyA 的答案中,您可以通过执行以下操作来减轻对递归和 c++11 版本中的空函数的需求...

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

Which should generate the same results as both of the other versions ( https://gcc.godbolt.org/z/hyAyiz ) with possibly better compile times on c++11.这应该产生与其他两个版本( https://gcc.godbolt.org/z/hyAyiz )相同的结果,在 c++11 上编译时间可能更好。

The compiler will create a new instance of printer for each call with different arguments and in the function will unfold the operator<< calls:编译器将为每个具有不同参数的调用创建一个新的打印机实例,并在函数中展开operator<<调用:

https://godbolt.org/z/Zz9Ik9 https://godbolt.org/z/Zz9Ik9

You can also see what happens here: https://cppinsights.io/你也可以在这里看到发生了什么: https : //cppinsights.io/

But ultimately - measuring will reveal if it leads to a performance gain.但最终 - 测量将揭示它是否会带来性能提升。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM