Snippet
template <typename CallableType, typename... Args>
auto invokeTest(CallableType&& fn, Args&&... args)
{
return std::invoke(fn, std::forward<Args>(args)...);
}
Is std::forward<Args>
needed here?
Or is it enough to write
template <typename CallableType, typename... Args>
auto invokeTest(CallableType&& fn, Args&&... args)
{
return std::invoke(fn, args...);
}
What are the differences?
Well, I'd say yes but it depends on the case.
You don't need forwarding in that case:
void bar(int);
int main() {
int i = 0;
invokeTest(bar, i);
}
But, you'll need forwarding for this case:
void foo(std::unique_ptr<int>);
int main() {
auto p = std::make_unique<int>();
invokeTest(foo, p); // Won't work, cannot copy unique_ptr
}
When writing std::invoke(fn, args...)
, the args...
are all lvalues, at which point I would recommend taking parameters by Args const&...
to be clearer.
If you forward, then you move the object that were rvalues in your parameters:
template <typename CallableType, typename... Args>
auto invokeTest(CallableType&& fn, Args&&... args)
{
return std::invoke(fn, std::forward<Args>(args)...); // all forward value caterories
}
invokeTest(foo, std::move(p)); // works.
If you use Args&&...
, use forwarding.