5

Consider the following two snippets:

Exhibit A:

template<typename CalcFuncT>
int perform_calc(CalcFuncT&& calcfunc)
{
    precalc();
    int const calc = calcfunc();
    postcalc();
    return calc;
}

int main()
{
    perform_calc([]{ return 5 * foobar_x() + 3; }); // toFuture
    perform_calc([]{ return 5 * foobar_y() - 9; }); // toPast
}

Exhibit B:

template<typename CalcFuncT>
int perform_calc(CalcFuncT&& calcfunc)
{
    precalc();
    int const calc = std::forward<CalcFuncT>(calcfunc)();
    postcalc();
    return calc;
}

int main()
{
    perform_calc([]{ return 5 * foobar_x() + 3; }); // toFuture
    perform_calc([]{ return 5 * foobar_y() - 9; }); // toPast
}

Diff:

    precalc();
-   int const calc = calcfunc();
+   int const calc = std::forward<CalcFuncT>(calcfunc)();
    postcalc();

What will be the difference (if any) between the generated code of these two pieces of code?

In other words what effect is the std::forward having in the above, if any?

Note this question is not asking what std::forward does in general - only what does it do in the above context?

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • [Source of the snippets in question](http://stackoverflow.com/a/7828809/636019). I use `std::forward<>` there because the caller may not necessarily always be a lambda (it may be a functor with overloaded `operator()`s); if the caller _is_ always a lambda, then there's no point in using `std::forward<>`. – ildjarn Mar 28 '12 at 23:48
  • @ildjarn: How do you overload `operator()`s, which can only be member functions, to differentiate on an rvalue `this` vs a lvalue `this`? – Andrew Tomazos Mar 28 '12 at 23:58
  • 2
    It's syntax new to C++11, introduced in [N2439](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm), colloquially known as "Extending move semantics to *this". Essentially, `&` and `&&` can be used as member function decorators (in addition to the usual `const` and `volatile`) to allow overloading based on the rvalue-ness or lvalue-ness of the object on which the member function is being invoked. – ildjarn Mar 29 '12 at 00:01

1 Answers1

4

The forward casts the lambda object to an xvalue prior to calling the operator()() on it. The lambda object's operator()() is not qualified with or overloaded on "&&" and so the forward should have no impact.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    It is best to avoid assumptions about functors, such as that the user will pass a lambda. Although rvalue-qualified `operator()` would be an oddity (implying a one-shot functor), example B is certainly more correct by allowing that case. – Potatoswatter Mar 29 '12 at 06:40