Зачем использовать вспомогательный помощник, а не просто вызвать функтор?

Как показано в "возможной реализации" std::apply, мы видим, что стандартная библиотечная функция std::invoke используется для вызова вызываемого объекта F.

Нужно ли в этой ситуации? если да, то по какой причине?

Каковы преимущества написания:

template<typename F, typename ... Args>
decltype(auto) func(F &&f, Args &&... args){
    return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

над

template<typename F, typename ... Args>
decltype(auto) func(F &&f, Args &&... args){
    return std::forward<F>(f)(std::forward<Args>(args)...);
}

?

Ответ 1

Указатель на элемент Callable и invoke (или invoke, так как скоро будет семипункт-точка Конструкция известна в Стандарте) магия обрабатывает этот случай (ну, четыре, и скоро это будет шесть случаев на самом деле), в то время как синтаксис вызова функции не делает.

Ответ 2

Я хочу дополнить T.C. ответ с синтаксическим примером:

struct X {
  int x;
  int foo(int a) const { return a + x; }
};

и у вас есть объект X и указатель на функцию-член, например:

X obj = X{1000};
auto fn = &X::foo;

и нужно вызвать func.

  • С синтаксисом вызова это не сработает:

    func_call(fn, obj, 24); // compiler error
    

    error: должен использовать '.' или '- > ' для вызова функции указатель-член в [...]

    Вместо этого вам нужно обойти это:

    func_call([obj, fn](int a) { return (obj.*fn)(a); }, 24);
    
  • Если у вас был метод invoke, вы могли просто написать:

    func_invoke(fn, obj, 24);