简体   繁体   中英

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. 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 .

At compile-time, several overloads of the function printer_cpp11 are generated, whereas a single function printer is needed using fold expression.

Is there an advantage in terms of performance in using fold expressions over the c++11 -style? Or can one assume that the compiler inlines all the overloads of printer_cpp11 , creating code with equivalent performance?

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).

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...

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.

The compiler will create a new instance of printer for each call with different arguments and in the function will unfold the operator<< calls:

https://godbolt.org/z/Zz9Ik9

You can also see what happens here: https://cppinsights.io/

But ultimately - measuring will reveal if it leads to a performance gain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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