Когда мне нужно: std:: forward вызов функции?

Фрагмент кода, который я видел в Effective Modern С++, имеет умную реализацию обоснования инструментария, чтобы создать таймер функции:

auto timeFuncInvocation = 
    [](auto&& func, auto&&... params)
    {
        start timer; 
        std::forward<decltype(func)>(func)(
            std::forward<decltype(params)>(params)...); 
        stop timer and record elapsed time; 
    };

Мой вопрос о std::forward<decltype(func)>(func)(...

  • По моему мнению, мы фактически отбрасываем функцию до ее первоначального типа, но зачем это нужно? Похоже, что простой вызов будет делать трюк.
  • Есть ли другие случаи, когда мы используем совершенную переадресацию для вызова функции?

Это выглядит как хороший вариант использования использования знакомого синтаксиса шаблонов в лямбда-выражениях, если мы хотим сделать тип таймера постоянной времени компиляции.

Ответ 1

Лучшее описание того, что делает std::forward<decltype(func)>(func)(...), будет сохранение категории значений аргумента, переданного лямбда.

Рассмотрим следующий функтор с ref-квалифицированными перегрузками operator().

struct foo
{
    void operator()() const &&
    { std::cout << __PRETTY_FUNCTION__ << '\n'; }

    void operator()() const &
    { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};

Помните, что в теле лямбда func есть значение lvalue (потому что оно имеет имя). Если вы не указали forward аргумент функции, то нельзя использовать вызываемую перегрузку &&. Более того, если квалифицированная перегрузка & отсутствовала, то даже если вызывающий передал вам экземпляр rvalue foo, ваш код не смог бы скомпилироваться.

Живая демонстрация