So far, I have considered passing and invoking a callable as
template <class Fct, class... Args> void f(Fct&& g, Args&&... args)
{
g(std::forward<Args>(args)...);
}
is the way to go. Now in this talk (at 34 min.) and in the std::invoke example implementation, I saw an equivalence of the above snippet that conditionally casts the callable to an rvalue reference before invoking it,
template <class Fct, class... Args> void f(Fct&& g, Args&&... args)
{
std::forward<Fct>(g)(std::forward<Args>(args)...);
}
I assume that this modification only affects closures, but I still don't understand why the second version is preferable: the cast only affects rvalue arguments and no state should be copied upon invocation, correct? I also checked whether std::function::operator() is overloaded on & and && to get a hint by a library alternative to the above snippets, but this is not the case.
Thanks in advance for hints and answers!
The point of perfect forwarding is to preserve the original information as much as possible.
g(std::forward<Args>(args)...); will drop the rvalue/lvalue information of the original function object, g will always be treated as lvalue.
This will cause observable effect, for example:
struct foo {
void operator()(int) & {
std::cout << "& called\n";
}
void operator()(int) && {
std::cout << "&& called\n";
}
};
foo{}(1) will invoke the second operator(). If you use your first approach without std::forward, f(foo{}, 1) will invoke the first operator().
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