I have a function template that takes an argument of some callable type, and uses std::bind
to make a new callable object with predefined argument values for the original callable. I've written it with a forwarding reference parameter and std::forward
, like this:
template <typename F>
auto make_example_caller(F &&f) {
return std::bind(std::forward<F>(f), 123, 456, 789);
}
The cppreference documentation for std::bind
says that the bound object "holds a member object of type std::decay<F>::type
constructed from std::forward<F>(f)
". Since std::bind
forwards the function to its internal data member, forwarding the same function to the std::bind
call in my own code seems reasonable and appropriate.
However, it's not clear what benefit that brings. If F
is a reference type, std::decay
removes the reference, so the bind object is going to store its own instance of the callable type. That instance will be constructed as a move if F
is an rvalue reference, or a copy if F
is an lvalue, and I can get the same result if I write my function like this:
template <typename F>
auto make_example_caller(F f) { // Note, no &&
return std::bind(std::move(f), 123, 456, 789); // move, not forward
}
Now my function's own f
parameter will be initialized by either move or copy depending on how the function is called, but either way I now have my own instance of the function object, which I can move into the bind object.
The latter way seems simpler, but I wonder if I'm missing something — especially since the same reasoning would apply to std::bind
itself, yet it takes an F&&
and forwards it, instead of taking an F
by value and moving it. Is there a disadvantage in doing it that way? Something that I'm not seeing?
Using a forwarding reference and std::forward
you can eliminate the creation of an extra object.
If you don't use a forwarding reference, you have three objects involved:
f
, constructed using the copy or move constructor as appropriateIf you use a forwarding reference with std::forward
, you eliminate the second one. There will only be two objects created:
While move-constructing an object may be cheaper than copy-constructing (depending on the type), it still contributes some overhead that perfect-forwarding can avoid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With