When to use std::invoke instead of simply calling the invokable?

Viewed 5467

As I understand, std::invoke allows me to do something like:

std::invoke(f, arg1, arg2, ...);

Is there a scenario when it's more advantageous than simply doing:

f(arg1, arg2, ...);
4 Answers

If the invocable is a pointer to a member function, then you need to do one of these:

(arg1->*f)(arg2,...);
(arg1.*f)(arg2,...);

Depending on what arg1 is.

INVOKE (and its official library counterpart std::invoke) was pretty much designed to simplify such messes.

You'd use std::invoke to support the caller of your code passing any callable, and not having to adapt their call site with a lambda or a call to std::bind.

std::invoke can be useful when you create a lambda and need to call it immediately. It the lambda is big, parentheses after it can be hard to observe:

[] (/* args */) {
    // many lines here
    // ...
} (/* args */)

vs

std::invoke(
    [] (/* args */) {
        // many lines here
        // ...
    },
    /* args */);
#include <iostream>
#include <functional>
template< class Callable, typename ... Args>{}

    //f(args...);   // if arg1 is a class object pointer 
                    // we should use it like this(arg1.*f)(args...); 

    std::invoke(f, args...); //  now  every thing is ok
}

void foo(char c) {
    std::cout << "foo called\n";
}

int main()
{
    struct S {
        int f1(char c) {
            std::cout << "S::f1 called\n";
        }
        void operator()(char c) {
            std::cout << "S::operator() called\n";
        }
    };
    int (S:: * fptr)(char c) = &S::f1;
    S  obj;

    dosomething(fptr, obj, 'a');
    return 0;
}

Trying to add on top of the two answers, one is giving a good theoretical explanation and the other is trying to provide a concrete example. Here is a good reason of why does std::invoke makes things better.

#include <functional>
#include <iostream>

struct foo
{
    void echo(){std::cout << "foo" << std::endl;};
};

int main()
{
    ////
    // Vanilla version of invoking .echo()
    foo(f);
    f.echo();

    ////
    // Pointer to *class* member function version
    void (foo::* pf)() =  &foo::echo;
    foo obj;
    
    (obj.*pf)();    // ugly
    // instead do ...
    std::invoke(pf, obj);

    // obj->echo(); <-- does not compile

    return 0;
}
Related