I wonder what's the right way of using a perfect forwarded functor? Here's two code snippet. Which one is the best, and if neither, what is the best form?
template<typename T, typename... Args>
void callMe(T&& func, Args&&... args) {
func(std::forward<Args>(args)...);
}
Or
template<typename T, typename... Args>
void callMe(T&& func, Args&&... args) {
std::forward<T>(func)(std::forward<Args>(args)...);
}
EDIT:
Will it impact overload resolution? If func
's operator()
has ref-qualifier for &&
or const &
, should I do the latter version and should I care about which overload I call?
Thanks!
Since ref-qualified operator()
exists, the first version could do the wrong thing. Consider:
struct C {
void operator()() && { std::cout << "rval\n"; }
void operator()() const & { std::cout << "lval\n"; }
};
callMe(C{});
I'm giving you an rvalue - and would expect to see "rval"
- but in the first version, you're always treating the function object like an lvalue - so I really see "lval"
.
So the correct solution would be the second - which forward
s func
as well.
In practice, I don't know how often ref-qualified member functions actually happen, so the former is likely fine.
Perfect forwarding is useful in the case where you are going to deliver an object (possibly an rvalue) to some other function, and you're not sure if it's an rvalue or an lvalue. In this case, you just use func
, so there's no gain or harm in forwarding it.
Remember, std::forward
is a conditional std::move
, which is only a cast to an r-value reference.
In addition, it's really only useful if there's a possibility that a copy or move constructor might be called for the thing you forward. In many cases, const T&
will do just fine.
edit:
As berry points out, it does matter if func
has ref-qualified operator()
. I've never seen or used a ref qualified method (as far as I know. It's extremely rare.) More in Barry's answer.
It'd read this also: What is "rvalue reference for *this"?
struct C {
void operator()() && { std::cout << "rval\n"; }
void operator()() const & { std::cout << "lval\n"; }
};
callMe(C{});
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