4

I'm seeing code that looks like this:

template<class Function>
void MyFunc(Function&& function) { function(...); }

What's the advantage of && here, as opposed to just copying the function by value? For reference, I'm using C++14.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
dromodel
  • 9,581
  • 12
  • 47
  • 65
  • 2
    Do you know about [move semantics](https://stackoverflow.com/questions/3106110/what-is-move-semantics)? – NathanOliver Jan 06 '20 at 19:16
  • 14
    Where is the lambda in your code? – Brian Bi Jan 06 '20 at 19:16
  • didnt find a dupe, but this is related: https://stackoverflow.com/questions/40819058/is-this-a-forwarding-reference – 463035818_is_not_an_ai Jan 06 '20 at 19:18
  • 1
    Do you know about [perfect forwarding](https://stackoverflow.com/questions/6829241/perfect-forwarding-whats-it-all-about)? – Moia Jan 06 '20 at 19:23
  • 1
    This is a function template. It is not a lambda expression. Though, from the name of the identifiers, you might be using `MyFunc` by providing it with a lambda expression. If this is the case, the question does not make this clear. – François Andrieux Jan 06 '20 at 19:23

1 Answers1

13

The problem comes from avoiding copies.

Imagine this:

auto lambda = [ptr = std::make_unique<int>(0)]() mutable {
    std::cout << *ptr;
    ptr = std::make_unique<int>(*ptr + 1); // why not?
};

MyFunc(lambda);                     // use it normally
MyFunc([]{ std::cout << " end"; }); // use by using a temporary lambda
lambda()                            // just call the function after that

If the signature is MyFunc(Function f), it would require a std::move and the lambda would not be useable after the call.

If the signature is MyFunc(Function const& f), it would not work since the lambda is mutable.

If it was MyFunc(Function& f) then the temporary would not work.

You're basically left with MyFunc(Function&& f).


The real question however is "Do I need to support all these cases?"

I would tell: most of the time no. Most of the time, receiving the lambda by value is the simplest and support almost every cases. This is the way the STL went.

Why? Because perfect forwarding of function objects is really hard to get perfect, and you cannot call the function multiple times in most of the cases in a pefectly generic way. I would perfect forward a function only if I want to wrap it, want to completely avoid copies and I expect function objects that are ref qualified to temporaries.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141