C++17 – std::apply() and std::invoke()

Written by on October 14, 2018 in C++, Programming with 0 Comments

Calling a function (or function object) dynamically, through a pointer known at runtime, is a common programming scenario. Almost all languages support this use case.

Lisp, for example, has apply and funcall.

Apply and Funcall in Lisp

Apply and Funcall in Lisp

When using apply, you can see that the arguments are passed via a separate list object. With funcall, however, the arguments are passed directly in line.

Likewise, Mathematica has Apply and Construct:

Apply and Construct in Mathematica

Apply and Construct in Mathematica

As you can see, the idea is quite similar to Lisp.

Even in C++ (prior to C++17), it has always been possible to call functions and methods dynamically through respective pointers. Take a look at the following example.

Pointers in C++

Pointers in C++

What is nice about C++17 is that it provides two methods apply and invoke (defined in the std namespace) that make dynamic method invocation more flexible and uniform. You will see that the behavior is quite similar to Lisp and Mathematica.

To make use of std::apply and std:: invoke you have to #include <functional>

Let us define a simple function that takes 3 integers and returns their sum. Let us also define a class (actually a struct) that has a public member function and an instance variable.

A Simple Function and A Class

A Simple Function and A Class

The apply method takes two arguments namely, the callable object that needs to be dynamically invoked, and the data structure that contains the arguments for the callable object. The data structure could be std::pair, std::tuple or std::array.

So let us create a tuple and array of 3 integers and see how to use apply

Calling std::apply

Calling std::apply

Notice that we cannot pass the original arguments directly in line when calling apply.

This is the difference between apply and invoke. invoke requires the arguments to be passed in line as if we are calling the function directly.

Calling std::invoke

Calling std::invoke

apply comes in quite handy if we are calling a varargs function such as printf. We can conveniently bundle all the arguments in a tuple and pass it to apply.

Calling a Varargs Functions

Calling a Varargs Function

Let us consider the case where instead of calling normal functions, we wish to invoke member functions. Remember that in order to invoke a member function, we need an object recipient (unless the function is static).

Both apply and invoke make this process quite simple and uniform.

Calling Member Functions

Calling Member Functions

Compare this with the traditional call syntax (shown within comments above). Hope you are able to appreciate the benefits of apply and invoke.

Implementations of these two functions depend on some fancy template coding tricks, but fortunately as users, we do not need to know the details. 

You can download my example source code here.

Have a great weekend!

Tags: , ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published.

Top