Выражение сгиба против рекурсии компиляции - PullRequest
2 голосов
/ 16 апреля 2019

В 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, создавая код с эквивалентной производительностью?

Ответы [ 3 ]

1 голос
/ 16 апреля 2019

Обе версии привели бы к одному и тому же коду кода из-за встраивания, поэтому производительность во время выполнения абсолютно одинакова: https://gcc.godbolt.org/z/VIHTvZ (код очищен от беспорядка потоков).

Однако время компиляции иОжидается, что использование памяти будет лучше с выражениями свертки, чем с рекурсивными экземплярами, и из-за этого, как правило, предпочтительнее выражение сгиба.Не говоря уже о том, что они также являются более понятными и легкими для понимания кода.

1 голос
/ 17 апреля 2019

Просто добавив к ответу @ SergeyA, вы можете уменьшить потребность в рекурсии и пустой функции в версии c ++ 11, выполнив что-то вроде ...

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 голосов
/ 16 апреля 2019

Компилятор создаст новый экземпляр принтера для каждого вызова с различными аргументами и в функции развернет оператор << </strong> вызывает:

https://godbolt.org/z/Zz9Ik9

Вы также можете увидеть, что происходит здесь: https://cppinsights.io/

Но в конечном итоге - измерение покажет, приведет ли это к повышению производительности.

...