11

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)...);
}

?

T.C.
  • 133,968
  • 17
  • 288
  • 421
RamblingMad
  • 5,332
  • 2
  • 24
  • 48

2 Answers2

8

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
4

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);
    
Community
  • 1
  • 1
bolov
  • 72,283
  • 15
  • 145
  • 224