As shown in the 'possible implementation' of std::apply
we see that the standard library function std::invoke
is used to invoke the callable object F
.
Is it needed in this situation? if so, for what reason?
What are the benefits of writing:
template<typename F, typename ... Args>
decltype(auto) func(F &&f, Args &&... args){
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
over:
template<typename F, typename ... Args>
decltype(auto) func(F &&f, Args &&... args){
return std::forward<F>(f)(std::forward<Args>(args)...);
}
?
A pointer to member is Callable
, and invoke
(or INVOKE
, as that soon-to-be-seven-bullet-point construct is known in the Standard)'s magic handles this case (well, four and soon to be six cases actually), while the function call syntax doesn't.
I want to complement T.C.'s answer with a syntactic example:
struct X {
int x;
int foo(int a) const { return a + x; }
};
and you have an X
object and a pointer to a member function, e.g.:
X obj = X{1000};
auto fn = &X::foo;
and need to call func
.
With the call syntax, this won't work:
func_call(fn, obj, 24); // compiler error
error: must use '.' or '->' to call pointer-to-member function in [...]
Instead you have to work around it:
func_call([obj, fn](int a) { return (obj.*fn)(a); }, 24);
If you had the invoke method, you could just have written:
func_invoke(fn, obj, 24);
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